首先要了解的是计数写实拷贝是在浅拷贝的基础上进行的。
什么是浅拷贝?用一张图来解释
计数写实拷贝是通过设置计数器Pcount来解决:
Pcount的初始值为0,s1指向空间时Pcount+1,即Pcount=1,s2拷贝s1时,Pcount再+1,即Pcount=2;进行析构时,- -Pcount,当Pcount的值为0时再进行析构。这样解决了浅拷贝中重复析构同一空间的问题。
实现计数写实拷贝的方法有两种:
1.在为s1开辟空间时,同时开辟空间保存Pcount,代码为:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class String
{
private:
char* _str;
int* _Pcount;
public:
String(char* str = "")
:_str(new char(strlen(str) + 1))
, _Pcount(new int(1)){//为Pcount开辟空间
strcpy(_str, str);
}
// s2(s1)
String(const String& s)//拷贝构造
:_str(s._str)
, _Pcount(s._pCount){
(*_Pcount++);//计数器++
}
void Realease(){
if (--(*_Pcount) = 0){
delete[]_str;
delete _Pcount;
}
}
~String(){
Realease();
}
String& operator=(const String& s){
if (_str != s._str){
Realease();
_str = s._str;
_Pcount = s._Pcount;
(*_Pcount++);
}
return *this;
}
void CopyOnWrite(){
if (*_Pcount > 1){
char* tmp = new char(strlen(_str) + 1);
strcpy(tmp, _str);
--(*_Pcount);
_str = tmp;
_Pcount = new int(1);
}
}
char& operator[](size_t pos){
CopyOnWrite();
return _str[pos];
}
const char* c_str(){
return _str;
}
};
void TestString()
{
String s1("hello");
String s2(s1);
String s3("world");
//s1[0] = 'x';
cout<<s1.c_str()<<endl;
cout<<s2.c_str()<<endl;
cout<<s3.c_str()<<endl;
s1 = s3;
s2 = s3;
}
int main(){
TestString();
}
2.在s1开辟空间时,用它的前四个字节来保存Pcount,不用开辟另一块空间,代码如下:
class String
{
private:
char* _str; // 引用计数在头上
public:
int& GetRefCount()
{
return *((int*)(_str - 4));
}
String(char* str ="")
:_str(new char(strlen(str) + 5)){
_str += 4;
strcpy(_str, str);
GetRefCount() = 1;
}
// s2(s1)
String(const String& s)
:_str(s._str){
GetRefCount()++;
}
~String(){
if (--GetRefCount() == 0){//为0时析构
delete[](_str - 4);
}
}
//s2 = s1
String& operator=(const String& s){
if (_str != s._str){
if (--GetRefCount() == 0){
delete[](_str - 4);
}
_str = s._str;
GetRefCount()++;
}
return *this;
}
const char* c_str(){
return _str;
}
void CopyOnWrite(){
if (GetRefCount() > 1){
--GetRefCount();
char* tmp = new char(strlen(_str) + 5);
tmp += 4;
strcpy(tmp, _str);
_str = tmp;
GetRefCount() = 1;
}
}
char& operator[](size_t pos){
CopyOnWrite();
return _str[pos];
}
};
void TestString2(){
String s1("hello");
String s2(s1);
String s3("world");
cout << s1.GetRefCount() << endl;
cout << s2.GetRefCount() << endl;
cout << s3.GetRefCount() << endl;
//s1 = s3;
//cout<<s1.GetRefCount()<<endl;
//cout<<s2.GetRefCount()<<endl;
//cout<<s3.GetRefCount()<<endl;
cout << s1[0] << endl;
cout << s1.GetRefCount() << endl;
cout << s2.GetRefCount() << endl;
cout << s3.GetRefCount() << endl;
}
int main(){
TestString2();
}