通常,我們會按如下方式書寫拷貝建構函式:
class lif // 預設建構函式
lif(const lif& l) : lif(l.lif) {} // 拷貝建構函式
private:
int lif;
};
這是正確的。但是,如果資料成員包含指標型別的話,這種寫法就很危險了。
class lif // 為lif動態分配記憶體
lif(const lif& l) : lif(l.lif) {} // 拷貝建構函式
~lif()
private:
int* lif;
};lif l1;
lif l2(l1); // 程式結束析構l2時,程式將崩潰
在拷貝l1
生成l2
的時候,我們的建構函式只是簡單的把l1
的lif
成員的值賦予了l2
的lif
,也就是說,它們儲存的都是l1
構造時分配的位址,當兩者之中的某個物件被銷毀時,建構函式正常執行,資源被釋放,但之後如果另乙個物件也被析構,lif
的資源就會被重複釋放,lif
也就變成野指標。這種拷貝方式也稱為淺拷貝,即只拷貝空間,不拷貝資源。
為了防止指標型別的資料成員出現野指標錯誤,對應地便有了深拷貝操作,即在拷貝物件內容的同時為拷貝的內容分配新的資源。
class lif // 為lif動態分配記憶體
lif(const lif& l) : lif(new int(*l.lif)) {} // 深拷貝建構函式
~lif()
private:
int* lif;
};lif l1;
lif l2(l1);
注意到,在上面的拷貝建構函式中,我們為新物件的lif
成員分配了一塊新的記憶體,即完成了深拷貝。
從上面的例子可以得到兩種抽象的類行為:行為像值、行為像指標。
即類提供的建構函式是深拷貝,類的每個物件都有自己的乙份拷貝。對於這樣的類,它顯然需要:乙個深拷貝建構函式、乙個深拷貝賦值運算子過載、乙個可以釋放成員占用的資源的析構函式。
class lif
lif(const lif& l) : lif(new int(*l.lif)) {}
lif& operator= (const lif& l)
~lif()
private:
int* lif;
};
即類提供的是淺拷貝,但由於可能有多個物件成員值相同一段記憶體,所以我們不能在析構時簡單地釋放資源。為了解決淺拷貝帶來的野指標問題,需要引入一種技術——引用計數(reference count)。這也是c++11的智慧型指標shared_ptr的實現。
引用計數:
class lif
lif(const lif& l) :
lif(l.lif), referencecount(l.referencecount)
lif& operator= (const lif& l)
lif = l.lif;
referencecount = l.referencecount;
return *this; }
~lif()
}private:
int *lif;
unsigned *referencecount;
};
C 引用計數寫時拷貝
寫時拷貝技術原理 寫時拷貝技術是通過 引用計數 實現的,在分配空間的時候多分配4個位元組,用來記錄有多少個指標指向塊空間,當有新的指標指向這塊空間時,引用計數加一,當要釋放這塊空間時,引用計數減一,直到引用計數減為0時才真的釋放掉這塊空間。當有的指標要改變這塊空間的值時,再為這個指標重新分配自己的空...
String淺拷貝 引用計數
當類裡面有指標物件時,進行簡單賦值的淺拷貝,兩個物件指向同一塊記憶體,存在崩潰的問題!為了解決這個問題,我們可以採用引用計數。在引用計數中,每乙個物件負責維護物件所有引用的計數值。當乙個新的引用指向物件時,引用計數器就遞增,當去掉乙個引用時,引用計數就遞減。當引用計數到零時,該物件就將釋放占有的資源...
引用計數的寫時拷貝
首先我們需要知道什麼是寫時拷貝,通俗的說,就是寫的時候再拷貝。那到底什麼才是寫時拷貝呢?舉乙個很簡單的例子,就是建立乙個string類的物件,然後用這個物件再拷貝出多個物件,當然指標也會拷貝過去,造成多個物件指向同一塊空間,當對某個物件進行讀操作時,不會發生什麼問題,但當需要對某個物件進行寫操作時,...