寫時拷貝(copy on write)
阿新 • • 發佈:2019-01-04
寫時拷貝和傳統深拷貝的區別:深拷貝是,每建立一個物件,則開闢一塊空間,不管讀寫
而寫時拷貝是用一塊空間count計數指向同一塊空間指標的數量。
如果只讀不寫,則只需要開闢一次空間。效率很高,記憶體佔用的也少,如果指向同一塊空間的指標需要
修改其內容,則該指標會自己開闢一塊空間用於修改,不會影響原來的空間。
寫時拷貝有兩種方法
————————————————————————————————————————————————————
第一種:類中定義一個成員變數count,拷貝構造或者賦值的時候,讓兩個物件的變數都指向同一塊空間
用count計數管理寫時拷貝
但是這樣的缺陷比較明顯,每次構造出一個物件,則會有額外的4個位元組被開闢出來計數。會造成記憶體存在很多碎片#include <iostream> using namespace std; class String { public: String(char* str = "") :_str(new char[strlen(str)]+1) , _refCount(new int(1)) { strcpy(_str, str); } String(const String& str) : _str(str._str) ,_refCount(str._refCount) { (*_refCount)++; } ~String() { release(); } String& operator= (const String& s) { if (_str != s._str) { release(); _refCount = s._refCount; (*_refCount)++; _str = s._str; } return *this; } void release() { if ((*--_refCount) == 0) { delete[] _str; delete _refCount; } } private: char* _str; int* _refCount; };
所以推薦第二種
———————————————————————————————————————————————————
第二種:
在_str前附帶count的空間,每次開闢_str的空間則會開闢count的空間,共存亡。這樣就會解決記憶體碎片的問題
class String { public: String(char* str = "") :_str(new char[strlen(str)+5]) //多開闢5個位元組來存放count和字串末尾的\0 { *(int*)_str = 1; //將_str前count初始化為1 _str = _str+4; //然後讓_str指向count後的記憶體。要修改count時再返回來呼叫 strcpy(_str,str); } String(const String& s) :_str(s._str) { GetCount()++; } String& operator=(const String& s) { if(_str != s._str) { this->~String(); //如果該物件的_str的count為1則釋放,否則count-1,呼叫 _str = s._str; //析構即可 GetCount()++; } return *this; } ~String() //如果count不為1,則不釋放空間, 只將count-1 { if(GetCount()-- == 1) { delete[] (_str-4); //釋放時注意,從count處釋放,否則會釋放掉錯誤的空間 _str = NULL; } } int& GetCount() //用這個函式來取_str最前面4個位元組的count { return *((int*)_str-1); } void print() { cout<<_str<<endl; } //當需要改變其_str時,需要檢查count是否為1,也就是是否只有一個物件 指向該_str //如果不是,則額外開闢一塊空間用於改變該物件的_str private: char* _str; }; //測試 int main() { String s("abc"); String s1(s); String s2("cde"); s1 = s2; return 0; }
析構的時候注意