2013-08-29 64 views
3

我通常(嘗試)使用複製交換語言編寫異常安全的複製賦值運算符,並且我想知道在編寫移動賦值運算符時是否應該關注異常。 這裏有一個副本assignement操作符的例子:異常安全移動運算符

template<class T> 
CLArray<T>& 
CLArray<T>::operator=(const CLArray& rhs) 
{ 
    CLArray tmp(rhs); 
    std::swap(size_, tmp.size_); 
    std::swap(data_, tmp.data_); 
    return *this; 
} 

但對於移動assignement?我的意思是,如果在移動操作過程中在代碼的其他地方拋出異常,我會失去兩個對象的狀態嗎?所以,我必須首先創建一個本地副本,然後刪除一切,但新創建的CLArray ...

template <class T> 
CLArray<T>& 
CLArray<T>::operator=(CLArray<T>&& rhs) 
{ 
    size_ = rhs.size_; 
    data_ = std::move(rhs.data_); 
    return *this; 
} 

請注意,data_是一個std ::向量,並感謝您的答案!

回答

4

確實,如果移動構造函數可能拋出,提供異常保證可能很困難或不可能。

我建議按照標準庫的做法:記錄某些操作只有異常保證(或者,在某些情況下,只允許)如果移動構造T沒有拋出。通過複製對象來保證保證會破壞所有類型的移動賦值的好處,而不僅僅是可能拋出的(非常罕見的)移位賦值的好處。

+0

感謝您的回答,我完全明白爲什麼創建一個副本將愚蠢的移動assignement。 – Athanase

2

無論如何,您應該添加一個swap成員函數並利用(複製/移動)賦值運算符中的(複製/移動)構造函數。 (並把後面那些可能無法拋出的操作。)

例(這裏內嵌在類爲簡潔):

template<typename T> 
class CLArray { 
public: 
    void swap(CLArray& other) 
    { 
     std::swap(data_, other.data_); 
     std::swap(size_, other.size_); 
    } 

    CLArray(const CLArray& other) 
     : data_(other.data_), size_(other.size_) 
    { 
    } 

    CLArray& operator=(const CLArray& rhs) 
    { 
     CLArray(rhs).swap(*this); 
     return *this; 
    } 

    CLArray(CLArray&& other) 
     : data_(std::move(other.data_)) 
    { 
     size_ = other.size_; 
     other.size_ = 0; 
    } 

    CLArray& operator=(CLArray&& rhs) 
    { 
     CLArray(std::move(rhs)).swap(*this); 
     return *this; 
    } 

    // ... 

private: 
    std::vector<T> data_; 
    std::size_t size_; 
}; 

C9 Lectures: Stephan T. Lavavej - Standard Template Library (STL), 9 of n (rvalue references)(視頻和STL的言論和代碼中的註釋)。

你可能還想讀戴夫亞伯拉罕的文章Your Next Assignment…Exceptionally Moving!

+0

非常感謝代碼和鏈接! – Athanase