2011-10-05 43 views
4

編寫類(使用copy-and-swap idiom)時的一般指導原則是提供非拋出交換成員函數。 (Effective C++, 3rd edition, Item 25和其他資源)可以使用拋出交換成員實現嗎?

但是,如果我不能提供nothrow保證,因爲我的課程使用不提供交換操作的第三方類成員?

// Warning: Toy code !!! 

class NumberBuffer { 
public: 
    ... 
    void swap(NumberBuffer& rhs); 

public: 
    float* m_data; 
    size_t m_n; 
    CString m_desc; 
}; 

void swap(NumberBuffer& lhs, NumberBuffer& rhs) { 
    lhs.swap(rhs); 
} 

void NumberBuffer::swap(NumberBuffer& rhs) { 
    using std::swap; 
    swap(m_data, rhs.m_data); 
    swap(m_n, rhs.m_n); 
    swap(m_desc, rhs.m_desc); // could throw if CString IsLocked and out-of-mem 
} 

CString的交換不能進行無拋出,所以有關閉的機會,交換可能會失敗。

注:對於罕見的第三方類,使用智能PTR(平普爾)將是一種選擇,但 -

注:CString的是一個很好的例子,在他的腦子沒有人會(?)通過pimpl(smart ptr)開始持有像CString這樣的概念上簡單而無處不在的類的所有成員,因爲這看起來真的很糟糕 - 另一方面,沒有(短期到中期)機會讓CString被修改爲允許完全無丟包交換。

那麼,如果你不能幫助它,可以使用一個潛在的引用交換成員函數? (或者你知道解決這個難題的方法嗎?)

編輯:和:一個投擲交換成員可以使用複製和交換成語提供基本保證,如果不是強有力的保證?

+6

不是一個答案,但如果你可以離開'CString',那麼問題就會消失... –

+0

請注意,在類似的問題上,你會有一些相當短的年數當您嘗試爲您的課程實施C++ 11移動時遇到同樣的問題。如果成員不能不交換,那麼它有可能不會是不可移動的,因爲兩者非常相似。 –

回答

3

所以如果你無法提供幫助,可以使用可能的引用交換成員函數嗎? (或者你知道解決這個難題的方法?)

沒有什麼本質上與具有swap功能,可以潛在地拋出,但要注意,如果沒有在swap強異常保證,它不可能被使用以提供異常安全性,也就是說,它只能用作swap(也就是說,忘記該特定類的複製和交換習慣用法作爲提供強大異常保證的方式......但您仍然可以使用它以減少代碼量 - 並證明它不是異常安全的)

或者,您可以將CString變成了一個智能指針,它提供了一個無丟包swap(或者至少是強大的異常保證),這不是一個好的解決方案,但它至少會是異常安全的。最後,你可以通過使用任何其他的字符串庫來完全避開CString,它提供了你所需要的任何字符串庫,並提供了一個無丟包交換操作。

+0

+1您是否可以從異常安全到線程安全?或者這是一個錯字? –

+0

@ChristianRau:考慮到上下文可能的錯字......事實上,這是如此明顯,我下意識地讀*例外*安全:) –

+0

@ChristianRau:這是一個錯字,對此感到抱歉。我有點累了:) –

-2

您可以輕鬆地讓它拋出異常:

void NumberBuffer::swap(NumberBuffer& rhs) throw() 
{ 
    try 
    { 
     std::swap(m_desc, rhs.m_desc); //could throw 
     std::swap(m_data, rhs.m_data); 
     std::swap(m_n, rhs.m_n); 
    } 
    catch(...) 
    { 
    } 
} 

當然,這是沒有真正解決問題,但現在你至少有你不拋出交換;)

+1

除了'交換'不履行合同和*默默*失敗!愉快的時間找到這些錯誤!我建議你要麼限定你的例子如何*不*做或刪除答案。謝謝! –

+0

@Martin這並不意味着太嚴肅,我意識到評論會更好,但可以隨意投票。 –

+1

鑑於'throw()'異常規範,如果沒有try/catch,這會更好。這樣編譯器就會安排'std :: terminate'在被拋出的時候被調用,至少假設你沒有處於某種不兼容的MSVC模式。仍然可能不是主叫方想要的,但至少顯然有些事情是錯誤的。 –

2

投擲swap沒有什麼內在錯誤,它比沒有投擲的版本更有用。

複製和交換成語不需要swap是無投擲,以提供強大的例外保證。 swap只需提供強有力的例外保證。

難點在於,如果無法提供無投票保證,那麼很可能無法提供強有力的例外保證。使用臨時版本和三份副本進行的天真交換僅提供基本保證,除非複製操作提供了無丟包保證,在這種情況下,swap也是無丟包的。

+0

優秀點wrt。沒有丟與強。如果只有一個成員不提供無投票保證,那麼這只是交換(複製)的問題,首先要獲得強力保證。如果有多個成員,我認爲一個人運氣不好。 –

相關問題