淺拷貝,深拷貝和寫時拷貝(string類)

2021-08-18 08:16:25 字數 4601 閱讀 7198

淺拷貝

淺拷貝:編譯器只是直接將指標的值拷貝過來,結果多個物件共用了一塊記憶體,當乙個物件呼叫了析構函式將這塊記憶體釋放掉之後,另一些物件不知道這塊空間已經還給了系統,再次呼叫析構函式進行釋放時發現已經釋放了,就會造成程式崩潰。

所以,在類的成員中有指標型別的成員變數的時候,必須對其寫出顯式的拷貝建構函式和賦值運算子過載函式,否則,預設的拷貝建構函式和賦值運算子過載函式只會對該指標進行淺拷貝(即直接將指標的值拷貝過來),導致多個物件的指標變數實際上指的是同一塊空間,會引發一系列的問題甚至是程式崩潰

//string類淺拷貝版本

class string

~string()

}

};

void funtest()

以上**,就是典型的淺拷貝,我們可以看到s1,s2和s3的指標實際指向的都是同一塊位址

如此在最後呼叫析構函式釋放空間的時候就會導致程式崩潰

深拷貝

因為淺拷貝會引發種種的問題,所以這裡就引入了深拷貝。深拷貝會在構造其餘物件的時候,拷貝一塊和被拷貝物件一樣大的空間,並將空間內的內容拷貝過來。這樣不同的物件就會指向不同的資料塊

下面我們對上面的**進行一些修改,我們實現乙個自定義的拷貝建構函式以及乙個賦值運算子過載函式

class string

string(const string& s)

:_s(new char[strlen(s._s)+1])

string& operator=(const string& s)

return *this;

}

~string()

}

};

void funtest()

以上就是深拷貝的模式,我們可以看到s1,s2和s3中的指標分別指向的是不同的位址

在涉及到類中有指標型別的變數時,尤其是要對該類進行相關拷貝的操作時,一定要顯式的定義乙個拷貝建構函式或是賦值運算子過載,進行深拷貝,不能用淺拷貝!!!

另外深拷貝還有乙個簡潔版本的,可以避免strcpy的c風格字串帶來的一些容易混淆的地方

//string類深拷貝簡潔版本

class string

string(const string& s)

:_s(null)

string& operator=(const string& s)

return *this;

}

~string()

}

};

void funtest()

寫實拷貝版本的string類(引用計數)

寫時拷貝(copy on write),

在複製乙個物件的時候並不是真正的把原先的物件複製到記憶體的另外乙個位置上,而是在新物件的記憶體對映表中設定乙個指標,指向源物件的位置,並把那塊記憶體的引用計數字加1。

原理:採用引用計數的機制。當乙個string物件str1構造時,string的建構函式會根據傳入的引數在堆空間上分配記憶體,當有其他物件通過str1進行拷貝構造的時候,str1的引用計數會+1(即當有其他類需要這塊記憶體的時候,引用計數+1)。當有物件析構時,這個引用計數會-1。直到最後乙個物件析構時,引用計數為0,此時程式才會真正釋放這塊記憶體(前面的析構並沒有釋放該記憶體,而是讓引用計數-1)。

下面是寫實拷貝版本的string類**

//string類寫時拷貝版本

class string

inline void release()

}

public:

string(char* s = "")

:_pstr(new char[strlen(s) + 1 + 4])

//多開闢4個位元組存放引用計數

string(const string& s)

:_pstr(s._pstr)

//直接進行淺拷貝

string& operator=(const string& s)

return *this;

}

~string()

char* c_str()

//返回字串首位址

//寫時拷貝,要進行寫操作的時候再進行拷貝

char& operator(size_t index)

return *(_pstr + index);

}

};

ostream& operator<

void funtest()

測試結果如下

改變s3:

s1:hello s2:world s3:wcrld

改變s2:

s1:hello  s2:wbrld s3:wcrld

改變s1:

s1:hallo  s2:wbrld s3:wcrld

下圖表示建立一塊新的記憶體時所做的事情

淺拷貝,深拷貝,寫時拷貝

淺拷貝 拷貝構造時複製指標僅僅是對指標的值拷貝,而不開闢新的空間這樣就會造成在析構的時候。會對同一塊記憶體釋放兩次。深拷貝 拷貝構造時會開闢新的記憶體,並把記憶體中的值進行拷貝 寫時拷貝 就是當你在讀取一片空間時,系統並不會為你開闢乙個一模一樣的空間給你 只有在當你真正修改的時候,才會開闢一片空間給...

深拷貝 淺拷貝 寫時拷貝

在拷貝構造的時候,直接將原內容的位址交給要拷貝的類,兩個類共同指向一塊記憶體。缺陷 1 一旦對str2進行操作,str1的內容也會改變 2 析構時先析構str2,再析構str1,但是由於str1,str2指向同一塊記憶體空間,因此會導致對一塊記憶體進行兩次析構而出現錯誤 通過開闢和源空間大小相同的記...

淺拷貝,深拷貝,寫時拷貝

思想 我們用指標p申請了一塊記憶體空間,在用指標q指向了這一片記憶體空間,這時候這兩個指標指向的是同乙個記憶體空間,當需要釋放這塊記憶體空間的時候p會釋放一次,q也會釋放一次,這樣重複釋放就會引發程式的崩潰。我們通過一段 來理解淺拷貝 class person void test int main ...