当一个类的成员对象是一个指针对象时,进行简单赋值的浅拷贝,会将两个对象指向同一块内存,这样在析构时同一块内存就会析构两次,引发奔溃。
所以在进行指针对象的赋值时要深拷贝。
下面我来模拟实现以下深拷贝。
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;
};