為什麼會出現自我賦值呢?不明顯的自我賦值,是「別名」帶來的結果:所謂「別名」就是「有乙個以上的方法指涉物件」。一般而言如果某段**操作pointers或references而它們被用來「指向多個相同型別的物件」,就需要考慮這些物件是否為同乙個。實際上兩個物件來自同乙個繼承體系,它們甚至不需要宣告為相同型別就可能造成「別名」。因為乙個base class的reference或pointer可以指向乙個derived class物件。如果你嘗試自行管理資源,可能會掉進「在停止使用資源之前意外釋放了它」的陷阱。假設你建立乙個class用來儲存乙個指標指向一塊動態分配的點陣圖(bitmap):
class bitmap;
2:class widget;
下面是operator=的實現**:
2: widget::operator=(const widget& rhs)
3:
這份**表面上合理,但自我賦值時並不安全。operator=函式內的*this(賦值的目的端)和rhs有可能是同乙個物件。果真如此delete就不只銷毀當前物件的bitmap,它也銷毀rhs的bitmap。在函式的末尾,widget—它原本不該被自我賦值動作改變的—發現自己持有乙個指標指向乙個已被刪除的物件。
欲阻止這種錯誤,可以在operator=最前面增加乙個「正同測試」(identity test)達到「自我賦值」的檢驗目的:
2:
這個版本具備「自我賦值安全性」,但是仍然存在異常方面的麻煩。更明確地說,如果「new bitmap」導致異常,widget最終會持有乙個指標指向一塊被刪除的bitmap。
令人高興的是,讓operator=具備「異常安全性」往往自動獲得「自我賦值安全性」的回報。許多時候一群精心安排的語句就可以匯出異常安全的**。例如以下**,我們只需注意在賦值pb之前別刪除pb:
2:
現在,如果「new bitmap」丟擲異常,pb保持原狀。
在operator=函式內手工排列語句的乙個替代方案是,使用所謂的copy和swap技術:
class widget;
6: widget& widget::operator=(const widget& rhs)
7:
請注意:
(2)確定任何函式如果操作乙個以上的物件,而其中多個物件是同乙個物件時,其行為仍然正確。
Effective C 筆記 條款09
為方便採用書上的例子,先提出問題,在說解決方案。class transaction 7 8 transaction transaction base class 的建構函式之實現9 13 14 class buytransaction public transaction 假設在程式中 buytra...
Effective C 筆記 條款08
c 並不禁止析構函式吐出異常,但它不鼓勵你這樣做。考慮如下 class widget 假設這個可能吐出乙個異常5 6 7 void dosomething 8 當vector v被銷毀,它有責任銷毀其內含的所有widgets。銷毀第乙個丟擲異常,銷毀第二個丟擲異常 異常對c 而言太多了。其實,在兩個...
Effective C 筆記 條款07
這個規則只適用於polymorphic 帶多型性質的 base class身上。這種base class的設計目的是為了用來 通過base class介面處理derived class物件 假如我們在程式中設計factory 工廠 函式,讓它返回base class指標,指向新生成的derived ...