事情是這樣的:
博主今天回看以前實現過的string,當時就遇到了一個bug:
可見博主當時的破防。因為最近在集中復盤C++初階部分,就有點好奇年輕的時候自己寫的模擬string是什么樣。沒想到給我自己留了個bug。
現在來細看這個場景:為了測試自己寫的賦值拷貝現代寫法效果,有了這個函數。
void test11(){//現代構造的寫法string s("helloworld");string s2(s);// 現代拷貝構造cout << s2 << endl;string s3("cherry magic");s2 = s3;// 現代賦值拷貝cout << s2 << endl;}
當來到165行時——即我打算讓s3賦值給現有的對象s2,此時自然要調用我親手寫的賦值拷貝。


當我按F11,企圖跳進operator=里時,卻是來到了拷貝構造這里。
嗯?此舉何意啊——正常意料:我親手寫的賦值拷貝operator=傳的參數是傳值傳參(傳值(自定義類型string)傳參都要雷打不動先拷貝構造一份)

沒錯,拷貝構造我也寫出了現代寫法——避免這里長篇大論,現代寫法我幾句話說個大概,說不定讀者看完就能上手寫。
string tmp(s.c_str());//tmp建立在當前函數棧上,等當前函數結束,函數棧幀被銷毀,生命周期也結束了。
當這句話執行完,tmp就是存在于當前棧上,但內容是拷貝s的string對象。我們拷貝構造函數的目的,就是讓當前的*this(未構造的對象)拷貝傳入對象s的內容,完成對象初始化。
無論如何,當拷貝構造函數結束,*this是完全實例化,tmp卻要走向獨屬它的落幕(因為tmp是string自定義類型對象,它自動會調用析構完成資源釋放)。
tmp拷貝完了,*this還沒拷貝。怎么辦?把*this有個大膽的想法——
swap(tmp);// 完整寫 this->swap(tmp); 或者 (*this).swap(tmp);
看我的批注:*this用自己的成員函數將tmp和自己交換——交換了拷貝的內容。*this就這么輕輕一換完成了拷貝構造,tmp就拿著本來無用的信息去析構了。
我們繼續按F11,等此次拷貝構造結束——跳入operator=的參數就構造完成,我們就進入operator=看看問題出在哪。



tmp此時該走向獨屬于它的落幕——身為string家中的長(棧)子,它有自己的使命(*this是次子(bushi



其實剛剛那一步,可能有讀者看出不對勁了。tmp交換過來的內容,應該是完全沒被初始化的——怎么可能會有需要的釋放的資源?那個_str也是生得奇怪——恰好是隨機值,躲過了判空檢查,所以避無可避地執行了delete[] _str;
我今天在改這個代碼的時候,其實沒注意到這點:因為出了構造函數完成了參數的拷貝構造,我想著此時該進入operator=了。直接按下了F10——跳過了tmp的析構,直接出現了這一幕。
所以下意識判斷是operaor=的問題:這也是為什么我會當時寫下這句判斷——

真相是什么?
今天在改代碼的時候,我發現因為*this天生生得潦草,_str這個指針怎么生都是隨機值——所以tmp換到它的內容,必走析構里的delete[] _str;——這件事讓我很是苦惱,知道哪里出問題了,卻是下不了手。
有沒有什么方法?有的,只是我忘了(我懺悔)

初始化列表
我今天也是開眼了,拷貝構造也是構造。只要是構造函數,類型的成員變量就會走初始化列表——初始化列表存在的意義就是對成員變量定義。
身為變量,有了聲明自然要有定義。所以不管顯示寫初始化列表與否,成員變量都會被定義(即成員變量都會走初始化列表)。初始化列表是很客觀的存在,不是我們不寫就不存在的。
如果顯示寫初始化列表,相應成員變量都會被規定的值初始化;
如果不顯示寫,可以在聲明的位置給出缺省值——沒錯,這里的缺省值就是給未顯示寫在初始化列表的成員進行定義
- 如果聲明都不給缺省值了,那編譯器表示:“那我隨意了”——對于內置類型,編譯器會給它隨機值(取決于編譯器,行為不確定);對于自定義類型,會去調用它的默認構造(如果沒有默認構造,會編譯報錯)
想起來了,我再看我的string成員變量聲明——果然沒有聲明值,而且剛剛的拷貝構造也沒顯示初始化列表(完美地避開正確初始化機會)


再看效果:

我發現AI摘要比我寫得完整,但我想沒我寫得有趣:(對只是我想)
摘要:博主復盤自己早期實現的string類時,發現了一個隱藏bug。問題出現在拷貝構造函數的現代寫法中:當交換臨時對象tmp和未初始化的*this時,由于未顯式初始化_str成員變量,導致析構時delete了一個隨機地址。通過給成員變量添加缺省值,解決了這個因未初始化引發的未定義行為。文章詳細記錄了調試過程,揭示了C++構造函數初始化列表的重要性,以及顯示初始化成員變量的必要性。最終修復方案是為string類的成員變量添加了缺省值聲明,使程序得以正確運行。