深入浅出 String类

当一个类的成员对象是一个指针对象时,进行简单赋值的浅拷贝,会将两个对象指向同一块内存,这样在析构时同一块内存就会析构两次,引发奔溃。

所以在进行指针对象的赋值时要深拷贝。
下面我来模拟实现以下深拷贝。

class String
{
    public:
    String(const char* str = "")
    :_str(new char[strlen(str)+1])
    {
    strcpy(_str,str);
    }

    String(const String& s)
    :_str(NULL)
    {
    String tmp(s._str);
    swap(_str,tmp._str);
    }

    /*String& operator=(const String& s)
    {
    if(this != &s)
    {
    String tmp(s._str);
    swap(_str,tmp._str);
    }
    return *this;
    }*/
    String& operator=(String s)
    {
    swap(_str,s._str);
    return *this;
    }
    ~String()
    {
    if(_str)
    {
    delete[] _str;
    }
    }
    private:
    char* _str;
};

String 类的写时拷贝技术
在上面的程序代码中,每一次赋值或者拷贝都会进行拷贝。这样是一种极大的开销,所以衍生出了写时拷贝。
这里主要讲以下已经被摒弃的引用计数的写时拷贝。主要了解一下C++编程思想。

class String{
    private:
    char* _str;
    int* _refcount;
    size_t _size;
    size_t _capacity;
    public:
    String(const char* str = "")
    :_refcount(new int(1))
    {
    _size = strlen(str);
    _capacity = _size;
    _str = new char[_capacity+1];
    strcpy(_str,str);
    }
    String(const String& s)
    :_str(s.str)
    ,_refcount(s._refcount)
    ,_size(s._size)
    ,_capacity(s._capacity)
    {
    (*_refcount)++;
    }

    String& operator=(const String& s)
    {
    if(_str != s._str)
    {
    Rease();
    _str = s._str;
    _refcount = s._refcount;
    (*_refcount)++;
    }
    return *this;
    }

    void Rease()
    {
    if(--(*_refcount) == 0)
    {
    delete[] _str;
    delete _refcount;
    }
    }
    !String()
    {
    Rease();
    }
    vodi CopyOnWrite()
    {
    if((*_refcount) > 1)
    {
   char* newstr = newchar[strlen(_str)+1];
    strcpy(newstr,_str);
    (*_refcount)--;
    _str = newstr;
    _refcount = new int(1);
    }
    }
char& operator[](size_t pos)
{
CopyONWrite();
return _str[pos];
}


};

以上的这种方式,在每一个类对象的会有一个refcount,来纪录本数据块被引用的次数,以此来保证在浅拷贝的情况下,在析构时不会被多次析构。但是在多次构造和析构后会留下很多的内存碎片。是一个不好的地方,为此我们将引用开辟在数据块的头部,以减少内碎片。

//版本二

class String
{
public:
    String(const char* str="")
    :_str(new char[strlen(str)+1+4])
    {
    strcpy(str+4,str);
    _str += 4;
    GetRefCount() = 1;
    }
    String(const String& s)
    :_str(s._str)
    {
    GetRefCount()++;
    }
String& operator=(const String& s)
{
if(_str != s._str)
{
Rease();
_str = s._str;
GetRefCount()++;
}
return *this;
}
int& GetRefCount()
{
return *((int*)(_str-4));
}
void Rease()
{
if(--GetRefCount() == 0)
{
delete[] (_str-4);

}
}
private:
char* _str;
};

猜你喜欢

转载自blog.csdn.net/niukeming/article/details/79854861