1.写时拷贝的定义:
由于浅拷贝使多个对象共用一块内存地址,调用析构函数时导致一块内存被多次释放,导致程序奔溃。
写时拷贝,就是在写的时候(即改变字符串的时候)才会真正开辟空间(深拷贝),如果只对数据读取时,就对数据进行浅拷贝,也称写时拷贝。
写时拷贝技术是通过“引用计数”实现的,在分配空间的时候多分配4个字节,用来存放引用计数器,记录这块空间的引用次数。当有新的指针指向这块空间时,引用计数加一,当要释放这块空间时,引用计数减一(假装释放),直到引用计数减为0时才真正释放掉这块空间。当有指针要改变这块空间的值时,再为这个指针分配自己的空间(注意这时引用计数的变化,旧空间的引用计数减一,新分配的空间引用计数加一)。
2. string中的两种写时拷贝
#include<iostream>
#include<stdlib.h>
using namespace std;
class String
{
public:
String(char *str = "")
:_str(new char[strlen(str) + 5])
{
*(int *)_str = 1;
_str += 4;
strcpy(_str, str);
}
~String()
{
if (_str != NULL)
{
_Release();
}
}
String(const String& str)
{
_str = str._str;
++_GetRefCount();
}
String& operator=(const String& str)
{
if (this != &str)
{
_Release();
_str = str._str;
++ _GetRefCount();
}
return *this;
}
char& operator[](int index)//写时拷贝
{
if (_GetRefCount()>1)//当引用次数大于1时新开辟内存空间
{
--_GetRefCount();//原来得空间引用计数器减1
char *str = new char[strlen(_str) + 5];
strcpy(str+4, _str);
_str = str+4;
_GetRefCount()++;
}
return _str[index];
}
friend ostream& operator<<(ostream& output, const String& str)
{
output << str._str;
return output;
}
private:
int& _GetRefCount()
{
return *(int *)(_str - 4);
}
void _Release()
{
if (--_GetRefCount() == 0)
{
delete[] (_str-4);
}
}
private:
char *_str;
};