接前两篇深拷贝与浅拷贝,实现更加方便的写实拷贝
什么时候会写时才拷贝?很显然,当然是在共享同一块内存的类发生内容改变
时,才会发生CopyOnWrite。比如string类的[]、=、+=、+、操作符赋值,还有一些string类中诸如insert、replace、append等成员函数,包括类的析构时。修改数据才会触发CopyOnWrite。
第一种
引用计数法:
思路:
定义一个int*_pcount
,调用一次构造函数,++(*_pcount)
,调用一次析构函数,--(*_pcount)
,直至减为0,调用delete[]
释放对象,这种方法可以解决浅拷贝多次释放内存空间带来的内存泄漏问题。
代码实现:
//引用计数法
class String
{
public:
//构造函数
String(char *str)
:_str(new char[strlen(str) + 1])
, _pCount(new int(1))//初始化为1
{
strcpy(_str, str);
}
//拷贝构造函数
//s2(s1)
String(const String& s)
: _str(s._str)
, _pCount(s._pCount)
{
++(*_pCount);
}
void Realse()
{
if (--(*_pCount)==0)//如果只有一个对象引用这块空间,则直接释放,否则计数器--
{
delete[] _str;
delete[] _pCount;
_pCount = NULL;
_str = NULL;
}
}
//赋值运算符重载
//s2=s1
String& operator=(const String& s)
{
if (_str != s._str)
{
Realse();
_str = s._str;
_pCount = s._pCount;
++(*_pCount);
}
return *this;
}
//析构函数
~String()
{
Realse();
}
void CopyOnWrite()//写实拷贝
{
if ((*_pCount) > 1)
{
char *newstr = new char[strlen(_str) + 1];//新建空间
strcpy(newstr, _str);//直接拷贝
--(*_pCount);
_str = newstr;
_pCount = new int(1);//此时_pCount指向不同空间
}
}
//修改字符串中的字符
char& operator[](size_t pos)
{
CopyOnWrite();
return _str[pos];
}
const char* c_str()
{
return _str;
}
private:
char *_str;
int* _pCount;//引用计数
};
void TestCopyOnWrite()
{
String s1("1234");
String s2 = s1;
s1.operator[](2) = 's';
cout << s1.c_str() << endl;
cout << s2.c_str() << endl;
}
在监视窗口看:
结果为:
第二种
代码实现为:
class String
{
public:
String(char *str )
:_str(new char[strlen(str)+5])
{
_str += 4;//从第5个字节开始
strcpy(_str, str);
GetRfCount() = 1;//即相当于写法1的_pCount=1
}
//s2(s1)
String(const String& s)
:_str(s._str)
{
++GetRfCount();
}
//s2=s1
String& operator=(const String& s)
{
if (_str!=s._str)
{
if (--GetRfCount() == 0)
{
delete[](_str-4);
}
_str = s._str;
++GetRfCount();
}
return *this;
}
const char& operator[](size_t pos) const
{
return _str[pos];
}
void CopyOnWrite()
{
if (GetRfCount() > 1)
{
--GetRfCount();
char *tmp = new char[strlen(_str) + 5];
tmp += 4;//字符串从第五个字节开始存储
strcpy(tmp, _str);
_str = tmp;
GetRfCount()=1;
}
}
//获取前四字节值
int& GetRfCount()
{
return *((int*)(_str - 4));
}
const char* c_str()
{
return _str;
}
char& operator[](size_t pos)
{
CopyOnWrite();
return _str[pos];
}
~String()
{
if (--GetRfCount() == 0)
{
delete[](_str - 4);
}
}
private:
char *_str;
};
//测试部分
void Test4()
{
String s1("1234");
String s2(s1);
String s3("world");
//cout << s1.c_str() << endl;
//cout << s1.GetRfCount() << endl;
//cout << s2.c_str() << endl;
//cout << s2.GetRfCount() << endl;
s1 = s3;
cout<<s1.GetRfCount()<<endl;
cout<<s2.GetRfCount()<<endl;
cout<<s3.GetRfCount()<<endl;
s1.operator[](3) = 'w';
cout << s1.c_str() << endl;
}
结果为:
最后这里推荐一篇陈皓的文章,详解写实拷贝