C++的深淺拷貝和寫時拷貝你了解嗎
1.淺拷貝
淺拷貝:對于有申請空間的對象的類來說,是按照字節(jié)序依次拷貝過去的,并沒有另外申請一塊空間。因此,在調(diào)用析構(gòu)函數(shù)的時候會造成同一塊空間釋放兩次的情況,從而使程序崩潰。
如下實例:
class string { public: string(const char* str) { //構(gòu)造string類對象時,如果傳遞nullptr指針 //認為程序非法,此處斷言下 assert(str); _str = new char[strlen(str) + 1]; strcpy(_str, str); } ~string() { if (_str) { delete[] _str; _str = nullptr; } } private: char* _str; }; void test() { string s1("linmanman"); string s2(s1); }
運行看看,報錯了
分析錯因:
淺拷貝是指向同一塊空間的,這樣就會有倆個無法避免的問題:
1.析構(gòu)倆次空間,程序崩潰
2.其中一個的值被修改了,會影響到另外一個的值。
深拷貝:給每個對象單獨分配資源,就是給待拷貝的對象另開一片空間,再把原對象空間上的值拷貝過來,這樣在調(diào)用析構(gòu)函數(shù)的時候就不會產(chǎn)生沖突。
2.深拷貝
傳統(tǒng)寫法的string類的深拷貝是自己開空間,自己將拷貝的對象拷貝到待拷貝對象中。
string(const string& s) : _str(new char[strlen(s._str)+1]) { strcpy(_str, s._str); } string& operator=(const string& s) { if(this != &s) { char* pStr = new char[strlen(s._str) + 1]; strcpy(pStr, s._str); delete[] _str; _str = pStr; } return *this; }
現(xiàn)代寫法的string類的深拷貝堪稱是“移花接木”
string(const string& s) :_str(nullptr)//必須置空,因為_str開始是個隨機數(shù),交換給tmp._str后,釋放會引起問題 { string tmp(s._str);//直接利用構(gòu)造函數(shù),給tmp對象開辟了一塊空間 swap(tmp); } string& operator=(string s) { swap(s);//這個swap是咱們自己寫的哦 return *this; }
順帶提一嘴,各個編譯器深拷貝的底層實現(xiàn)略有差異(當然邏輯是一樣的)
VS 2013下的深拷貝
g++下的深拷貝
3.引用計數(shù)+寫時拷貝
寫時拷貝就是一種拖延癥, 是在淺拷貝的基礎(chǔ)之上增加了引用計數(shù)的方式來實現(xiàn)的。
引用計數(shù):用來記錄資源使用者的個數(shù)。在構(gòu)造時,將資源的計數(shù)給成1,每增加一個對象使用該資源,就給計數(shù)增加1,當某個對象被銷毀時,先給該計數(shù)減1,然后再檢查是否需要釋放資源,如果計數(shù)為1,說明該對象時資源的最后一個使用者, 將該資源釋放;否則就不能釋放,因為還有其他對象在使用該資源。
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
c++ dynamic_cast與static_cast使用方法示例
本文用示例講解了dynamic_cast、static_cast子類與基類之間轉(zhuǎn)換功能的使用方法2013-11-11C語言數(shù)據(jù)結(jié)構(gòu)二叉樹先序、中序、后序及層次四種遍歷
這篇文章主要介紹了C語言數(shù)據(jù)結(jié)構(gòu)二叉樹先序、中序、后序及層次四種遍歷方式,具有一定的知識性參考價值,需要的小伙伴可以先看一下2022-02-02