注:C語言實現的PHP變數的賦值過程中,就涉及到了 深拷貝和淺拷貝
位拷貝拷貝的是地址(也叫淺拷貝),而值拷貝則拷貝的是內容(深拷貝)。深拷貝和淺拷貝可以簡單理解為:如果一個類擁有資源,當這個類的物件發生複製過程的時候,資源重新分配,這個過程就是深拷貝,反之,沒有重新分配資源,就是淺拷貝。
位拷貝,及"bitwise assignment"是指將一個物件的記憶體映像按位原封不動的複製給另一個物件,所謂值拷貝就是指,將原物件的值複製一份給新物件。 在用"bitwise assignment"時會直接將物件的記憶體映像複製給另一個物件,這樣兩個物件會指向同一個記憶體區域,當一個物件被釋放後,另一個物件的指標會成為空指標。這時,就應該編寫operator=和copy constructor來實現值拷貝 .
預設的拷貝建構函式"和"預設的賦值函式"均採用"位拷貝"而非"值拷貝"的方式來實現,倘若類中含有指標變數,這兩個函式註定將出錯。
當用一個已初始化過了的自定義類型別物件去初始化另一個新構造的物件的時候,拷貝建構函式就會被自動呼叫。也就是說,當類的物件需要拷貝時,拷貝建構函式將會被呼叫。以下情況都會呼叫拷貝建構函式:
1、一個物件以值傳遞的方式傳入函式體
2、一個物件以值傳遞的方式從函式返回
3、一個物件需要通過另外一個物件進行初始化。
如果在類中沒有顯式地宣告一個拷貝建構函式,那麼,編譯器將會自動生成一個預設的拷貝建構函式,該建構函式完成物件之間的位拷貝。位拷貝又稱淺拷貝。自定義拷貝建構函式是一種良好的程式設計風格,它可以阻止編譯器形成預設的拷貝建構函式,提高原始碼效率。
如果沒有自定義複製建構函式,則系統會建立預設的複製建構函式,但系統建立的預設複製建構函式只會執行"位拷貝",即將被拷貝物件的資料成員的值一一賦值給新建立的物件,若該類的資料成員中有指標成員,則會使得新的物件的指標所指向的地址與被拷貝物件的指標所指向的地址相同,delete該指標時則會導致兩次重複delete而出錯。下面拿這個經典示例:
Class String{
public:
String(const char *ch=NULL);//預設建構函式
String(const String &str);//拷貝建構函式
~String(void);
String &operator=(const String &str);//賦值函式
private:
char *m_data;
};
如果以String為例定義strA和strB
int main()
{
String strA("hello");
String strB("world");
strB = strA;
// 結果導致 strA 和 strB 的指標都指向了同一個地址
// 函式結束析構時
// 同一個地址被delete兩次
return 0;
}
如果不主動編寫拷貝建構函式和賦值函式,編譯器將以"位拷貝"的方式自動生成預設的函式。倘若類中含有指標變數,那麼這兩個預設的函式就隱含了錯誤。以類String的兩個物件strA,strB為例,假設strA.m_data的內容為"hello",strB.m_data的內容為"world". 現將strA賦給strB,預設賦值函式的"位拷貝"意味著執行strB.m_data =strA.m_data.這將造成三個錯誤:
● strB.m_data 原有的記憶體沒被釋放,造成記憶體洩露;
● strB.m_data和strA.m_data指向同一塊記憶體,strA或strB任何一方變動都會影響另一方;
● 在物件被析構時,m_data被釋放了兩次。
對於編譯器,如果不主動編寫拷貝函式和賦值函式,它會以位拷貝的方式自動生成預設的函式。
另外一篇文章 http://blog.csdn.net/bluescorpio/article/details/4322682