接前兩篇深拷貝與淺拷貝,實現更加方便的寫實拷貝
什麼時候會寫時才拷貝?很顯然,當然是在共享同一塊內存的類發生內容改變
時,纔會發生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;
}
結果爲:
最後這裏推薦一篇陳皓的文章,詳解寫實拷貝