2012-07-14 36 views

回答

21

在一般實現中,假設T的任何操作都可以使用throw,那麼您不能提供強大的異常保證,這意味着完全保留狀態與異常事件操作之前的狀態完全相同。即使在T每個操作提供了強大的異常保證:

template<class T> 
void swap (T &a, T &b) 
{ 
    T temp (a);   // [1] 
    a = b;    // [2] 
    b = temp;   // [3] 
} 

如果[1]兩罰全中,輸入保持不變,這是很好的。如果[2]拋出,並且假設強有力的例外保證,那麼這些值仍然未被觸發,這是很好的。但是,如果拋出[3],a已被修改,這意味着在異常傳播到堆棧之後,調用者將留下一個既不是原始狀態也不是最終狀態的狀態。


編輯:此外,我們如何解決它呢?

沒有通用的解決方案。但在大多數情況下,您可以爲您的類型提供異常安全swap操作。考慮vector<T>,它通過使用三個指針(begin,end,capacity)在內部管理它的狀態。一般swap以上皆可拋(不分配,用於內部T建設者可能會引發...),但它是微不足道提供無拋出swap實現:

template <typename T> 
class vector { 
    T *b,*e,*c; 
public: 
    void swap(vector<T>& rhs) { 
     using std::swap; 
     swap(b, rhs.b); 
     swap(e, rhs.e); 
     swap(c, rhs.c); 
    } 
//... 
}; 
template <typename T> 
void swap(vector<T>& lhs, vector<T>& rhs) { 
    lhs.swap(rhs); 
} 

由於指針的複製不能扔,上面的swap提供了無投票保證,如果您始終按照上述模式執行swapusing std::swap;後跟非限定呼叫swap),那麼它將被ADL視爲比std::swap更好的匹配。

+1

+1我會寫同樣的東西。與[本文](http://www.boost.org/community/exception_safety.html)的鏈接將是一種幫助,對那些想要詳細瞭解基於合同的異常安全的人員很有幫助。 – Nawaz 2012-07-14 17:30:58

2

丹尼爾是對的,當然。

但是你不應該忘記,當涉及到異常安全時,swap主要被認爲是解決方案的一部分(「複製和交換習慣用法」),而不是問題。剩下的問題是,如果你採用這個習慣用法,你必須確保交換的拷貝構造函數可以調用,不要拋出異常,這是Daniel解釋的原因。

參見:What is the copy-and-swap idiom?

0

異常的來源一直是解釋

,但你可以通過鑄造參數unsigned byte*和字節加快調換字節sizeof(T)注意:不調用任何構造避免異常或在其上可能違反某些先決條件時,有一些參考自正在進行的對象的析構函數(當a指向b交換a之後將指向a

這就是D標準庫中的交換是如何做到的(在檢查自引用之後)