什么是浅拷贝?
例如下面的代码,:
class AA
{
private:
int* _a = new int[2];
};
int main(void)
{
AA a1;
AA a2(a1);
system("pause");
return 0;
}
我们看到对象a1和a2地址一样,指向同一块空间
当类中的成员变量包括指针时,而又没有定义自己的拷贝构造函数,那么在拷贝一个对象的情况下,就会调用其默认拷贝构造函数,其实这个函数没做什么事,只是对其成员变量作了个简单的拷贝,也就是所谓的位拷贝,它们指向的还是同一个存储空间,当对象析构时,就会析构多次!
【深拷贝】
深拷贝是为了解决浅拷贝中同一块空间多次释放的问题。
例如:
String(const String& str)
{
_str = new char[strlen(str._str) + 1];
strcpy(_str, str._str);
}
我们看到,this->_str拥有了属于自己的一块空间。
【深拷贝的现代写法】
String(const String& str)
{
_str = NULL;
String tmp(str._str);
swap(_str, tmp._str);
}
【写时拷贝】
何为写时拷贝??深拷贝是补充了浅拷贝的不足,写时拷贝其实也就是补充一点深拷贝的不足。其实写时拷贝的意思就是:当你读取到这个空间的时候,并不会开辟出一个一模一样的空间出来给你,当你真正需要拷贝的时候,那么他就会开辟出空间给你。也就是拖延版的深拷贝。
写时拷贝代码
class String1
{
public:
String1(const char* str = "")//构造函数
:_str(new char[strlen(str) + 1])
, _refCount(new int(1))
{
strcpy(_str, str);
}
String1(String1& s)//拷贝构造
:_str(s._str)
, _refCount(s._refCount)
{
(*_refCount)++;
}
~String1()//析构
{
if (--(*_refCount) == 0)//当_refCount=1时,说明该空间只属于一个对象,可以被释放了
{
delete[] _str;
delete _refCount;
}
}
private:
char* _str;
int* _refCount;
};
【赋值运算符重载】要考虑多种情况:
String1& operator =(const String1& s)
{
if (_str != s._str)
{
if (--(*_refCount) == 0)
{
delete[] _str;
delete _refCount;
}
_str = s._str;
_refCount = s._refCount;
*(_refCount)++;
}
return *this;
}
写时拷贝
void CopyOnWrite()
{
if (*_refCount > 1)
{
char* newstr = new char[strlen(_str)];
strcpy(newstr, _str);
(*_refCount)--;
_str = newstr;
_refCount = new int(1);
}
}
第二种方式
开辟一个空间,前面4个字节为计数器count,剩下的为字符串_str的空间,用法与分开相同。
String(const char* str = " ")
:_str(new char[strlen(str)+5]
{
strcpy(_str+4,str);
*((int*)_str) = 1;
_str += 4;
}
String(const String & s)
:_str(s._str)
{
(*(int*)(_str-4))++;
}
~String()
{
if(--*((int*)(_str-4))==0)
{
delete[](_str-4);
}
}
String & operator = (const String & s)
{
if(_str != s.s_str)
{
if(--GetRefCount() == 0)
{
delete[] (_str-4);
}
_str = s.s_str;
GetRefCount()++;
}
return *this;
}
int& GetRefCount()
{
return (*(int *)(_str-4));
}