條款11:在operator=中處理自我賦值的現象
? ? ? ? ? ?雖然我們在平時可能不會出現顯示自我賦值的現象,當加入指針或者引用時,可能會出現不同的指針或引用指向同一對象(對象的不同別名),這時候我們就得考慮對象是否是同一個;考慮到要保證系統的自我賦值安全性和異常安全性的角度,可以采用的方案是:將原來的被賦值對象做一個副本,然后讓被賦值對象指向復制對象,最后刪除副本即可,代碼如下:
? ? ? ? widget& widget::operator=(const widget & rhs){
? ? ? ? ? ? ? ? ? ? bitmap *porig=pb;? ? ? ? ? ? ? ? ? ? ? ? ? //pb為類widget的一個類型為bitmap的指針
? ? ? ? ? ? ? ? ? ? pb=new? bitmap(*rhs.pb);
? ? ? ? ? ? ? ? ? ? delete porig;
? ? ? ? ? ? ? ? ? ? return *this;
? ? ? ? ? }
? ? ? ? ? ?最好的方法是采用copy and swap的方案,代碼如下:(方案1采用傳引用的方法,方案2采用傳值的方法
? ? ? ?void swap(widget &rhs)? {....};? ? //交換rhs和*this的數據;
? ? 方案1: widget &widget::operator=(const widget & rhs){? ? ? ? ? ? ? 方案2: widget&widget::operator=(widget rhs)
? ? ? ? ? ? ? ? ? ? widget temp(rhs);? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? {? ?
? ? ? ? ? ? ? ? ? ? swap(temp);? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?swap(rhs);? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? ? ?return *this;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? return *this;
? ? ? }? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
條款12:復制對象時勿忘其每個成分
? ? ? ? ? 當自己定義copy函數時(copy構造和copy assignment),編譯器不再給我們提供新的copy函數,因此在拷貝的過程中,我們要確定所有的成員變量都被拷貝;
? ? ? ? ? 當我們為class增添新的成員變量時,我們需要修改我們所有的copy函數,構造函數,采用繼承的方式可以避免代碼的過多修改,但是你必須保證base class的成員變量也被初始化,也就是在derived class的拷貝函數初始化列表或者函數體中調用base class的拷貝函數;如果不這樣做,derived class在構造copy函數的時候會調用base class的default copy函數,但是base class的copy函數是被阻止的,因此此時編譯器會報錯;
? ? ? ? ?結論:當我們寫一個自定義的copy函數的時候,確定幾點:1)復制所有的local成員變量;2)調用所有base class內適當的copy函數;
? ? ? ? ? ? 不要令copy assignment去調用copy構造函數;也不要讓copy構造函數去調用copy assignment;
? ? ? ? ? ?當copy assignment和copy 構造函數有相近的代碼時,可以把相同的代碼變成新的成員函數,這樣的函數通常為private且常命名為init;
條款13:以對象管理資源
? ? ? ? ? ? ?以singleton(單例模式)的factory function為例,函數返回的是一個heap-base的指針,用戶在使用完這個對象之后需要把這個指針刪除,如何保證這個指針所指向的資源被刪除呢?可選用的方法是把:把資源放進對象中,利用C++的“析構函數自動調用機制”保證資源被釋放;
? ? ? ? ? ? ?C++標準程序庫中提供auto_ptr(類指針對象,也稱為智能指針),其析構函數自動對其所指對象調用delete,常見的智能指針有unique_ptr,shared_ptr;weak_ptr;
? ? ? ? ? ? 以對象管理資源的兩個關鍵想法:1)獲得資源后立刻放進管理對象內,實際上“以對象管理資源”的觀念通常被稱為“資源取得時機便是初始化時間(resource acquisition isinitialization RAII)”;2)管理對象運用析構函數確保資源被釋放(在析構函數釋放資源時,可能會出現異常,正確處理析構函數中拋出異常的情況);
? ? ? ? ? ? auto_ptr的特性是被銷毀(調用copy函數時會發生)時自動刪除它的所指之物,并將自己的指針指向nullptr,因此不要讓對個auto_ptr指向同一個對象,如果這樣可能會出現對象被刪除一次以上;auto_ptr的性質是始終只有一個指針取得資源的唯一擁有權;
? ? ? ? ? auto_ptr的替代方案是:引用型計數指針(reference-counting smart pointer,RCSP),該指針特性就是持續追蹤多個指針指向同一資源,并在無人指向該資源時釋放資源,但是RCSP無法打破環形引用(也就是類中互相指向的問題,可用weak_ptr來解決這一現象);
? ? ? ? ?由于以對象管理資源在析構函數中執行的是delete而非delete[],因此動態分配的數組無法通過這種方式來實現內存釋放,只能通過自己手工釋放內存資源;