目錄
(1)條款08:別讓異常逃離析構函數(這條理解的不好,看官可忽略或者幫我理解理解)
(2)條款09:絕不在構造和析構過程中調用virtual函數
(3)條款10:令operator = 返回一個reference to *this。
人生美好,今日之工乃爲明日之秀,666
接上篇文章https://mp.csdn.net/console/editor/html/106558956
(1)條款08:別讓異常逃離析構函數(這條理解的不好,看官可忽略或者幫我理解理解)
簡單的說就是析構函數出BUG可能會導致程序退出的時候崩潰或者中斷。
舉個例子,你寫了一個程序,每次點擊一個按鈕就會,創建100個座位的屋子,classA申請10個,classB申請10個空間,點擊關閉析構的時候先析構classA,再析構classB,如果classA的析構函數出現異常,就無法進行classB的析構,導致classB析構失敗,程序造成內存泄漏。(等等!我程序異常退出了,內存都釋放了,所以異常退出這個例子並沒有很嚴重,析構一旦失敗程序就會結束,這個可能是平臺等相關的,後續有機會討論)
書中給出的辦法,比如我這裏想確保數據庫已經被關閉,那麼就需要再來一個函數close來確保程序關閉數據庫。
(2)條款09:絕不在構造和析構過程中調用virtual函數
在構造和析構函數中不要調用虛函數。
在C++繼承關係中,父類指針實例化子類對象是會先走父類的構造函數的,走父類的構造函數時如果調用虛函數調用的則是父類的虛函數。與我們想要達成的效果(調用子類的重載虛函數)不同。
如下:
父類
class MyClass
{
public:
MyClass();
virtual void setData();
int b;
};
MyClass::MyClass()
{
setData();
}
void MyClass::setData()
{
b = 10;
}
子類:
class MySon : public MyClass
{
public:
MySon();
virtual void setData() override;
};
MySon::MySon()
{
}
void MySon::setData()
{
b = 10*10;
}
我們調用:
MyClass *p_myClass = new MySon;
printf("%d\n",p_myClass->b);
打印結果爲10。
這裏可以看到,我們在調用過程中調用的是父類的虛函數實現,而不是子類的虛函數實現。
解決方案:就別在析構函數中寫虛函數。或者讓子類也走一遍該函數(不好管理)。可以用一個init函數來讓用戶手動調用想要調用的函數。
(3)條款10:令operator = 返回一個reference to *this。
這個是爲了連續賦值功能。
Widget & operator=(const Widget & rhs)
{
...//賦值操作
return *this;//返回自身
}
(4)條款11:在operator=中處理“自我賦值”
這裏就是用到swap函數來處理。
先說問題,如果自我賦值了,可能會導致“指針指向一個已經被刪除的對象”。
(5)條款12:複製對象時勿忘其每一個成分
這條適用於拷貝構造函數或“=”運算符。在寫這些函數的時候要確保每一個成員變量都被正確拷貝複製。
注意:不要用一個賦值函數來調用另一個賦值函數,應該將重複代碼再起一個函數供這兩個函數調用。