2014-04-23 97 views
3

我讀過關於異常安全並得出以下問題:矢量分配和異常安全

在A類m_value和M_DATA應該是相互一致。但如果

m_data = data; 

拋類不變將被打破。

class A 
{ 
public: 
    void Set(const std::vector<unsigned int>& data) 
    { 
     m_value = ComputeValue(data); 
     m_data = data; 
    } 
private: 
    int m_value; //That should be consistent with vector 
    std::vector<unsigned int> m_data; 
} 

我應該用一些副本和交換的變體來保護這段代碼嗎? 在這樣的每一行代碼中使用複製和交換是否是好的決定,還是可以按照原樣使用此代碼?

這是我的解決辦法,但我不知道,我應該使用它或它是多餘的複雜性:

void Set(const std::vector<unsigned int>& data) 
{ 
    std::vector<unsigned int> tmp_data(data); 
    m_value = ComputeValue(tmp_data); 
    m_data.swap(tmp_data); 
} 

附加:

另一個問題: 我應該寫我自己的異常安全的分配新建分配FY運營商或交換的功能,使其可以使用這樣的:

class B 
{ 
public: 
    SetA(const A& a) 
    { 
     A tmp_a(a); 
     m_a.swap(tmp_a); 
    } 
private: 
    A m_a; 
} 

而在A級

void A::swap(A& rhs) 
{ 
    using std::swap; 
    swap(m_data, rhs.m_data); 
    swap(m_value, rhs.m_value); 
} 
+1

它取決於'ComputeValue'的合同。它是什麼? – Deduplicator

+0

ComputeValue不合適,如果它是合同的意思。 – Nosturion

+0

在這種情況下,交換是多餘的。當沒有任何東西可以拋出時,不需要或沒有意識防止異常。 – Deduplicator

回答

2

如果ComputeValue可以拋出,使用copy-and-swap idiom是爲函數提供強大異常安全保證的最簡單方法。但是,不要通過const引用傳遞並在函數中創建副本,最好是通過值傳遞向量,因爲如果函數傳遞了r值,則允許編譯器調用移動構造函數。

void Set(std::vector<unsigned int> data) 
{ 
    m_value = ComputeValue(data); 
    m_data.swap(data); 
} 

如果ComputeValue不能扔,那麼這一切的麻煩是沒有必要,你可以計算新值之前剛剛分配矢量(由常量引用傳遞)的成員變量。如果A的複製分配操作符提供了強大的異常安全保證(它應該),我認爲沒有任何好處,只是將函數參數賦值給成員變量,這也很容易實現使用copy-and-swap成語。

+0

請看看。 OP說'ComputeValue'不能拋出。 – Deduplicator

+0

@Deduplicator更新了我的答案以反映這兩種情況。 –