2016-09-18 71 views
0

可能這已被問及已答覆,但我不知道要搜索什麼。使用非指針數據成員移動語義

如果數據成員已經定義了移動賦值運算符,可以將移動語義用於非指針數據成員嗎?

假設我有一個類M定義M::operator=(M&&)這樣的:

template <class T> 
class M 
{ 
public: 
    M() 
    { 
     mem_M = new T; 
    } 

    M& operator=(M&& src) 
    { 
     if (this != &src) 
     { 
      mem_M = src.mem_M; 
      src.mem_M = nullptr; 
     } 
     return *this; 
    } 

private:  
    T* mem_M; 
}; 

現在很明顯,我可以有一個類C<T>這樣,一招構造,使得沒有用T的舉動賦值操作符:

template <class T> 
class C 
{ 
public: 
    C() 
    { 
     mem_C = new T; 
    } 
    C (C&& rhs) 
    { 
     mem_C = rhs.mem_C; 
     rhs.mem_C = nullptr; 
    } 

private: 
    T* mem_C; 
}; 

但是,如果我想C<T>::mem_C到不是一個指針,但一個普通的成員,我將如何應對布展功能C<T>::mem_C?我當然可以調用移動賦值運算符T::operator=(T&&)將字段mem_C從一個實例移到另一個實例,但是如何正確地重置傳遞給C<T>::C(C&&)C實例?

這至少看起來我錯了:

template <class T> 
class C 
{ 
public: 
    C() 
    { 
     mem_C = T(); 
    } 
    C (C<T>&& rhs) 
    { 
     mem_C = std::move(rhs.mem_C); 
     rhs.mem_C = T();   // ?? like this? 
    } 

private: 
    T mem_C; 
}; 

那麼,什麼是對移動功能的非指針數據成員重置符合標準的方法是什麼?

+0

指針是「普通成員」的子集。你似乎在問移動類類型和非類類型之間的區別 –

+0

'mem_C = T();'應該被移除,對象已經被構建,所以這隻會浪費時間和資源。 –

+0

在這種情況下,您可以也應該使用默認移動賦值運算符(請參見[Rule of zero](http://en.cppreference.com/w/cpp/language/rule_of_three)) –

回答

3

包含類型的移動賦值/構造函數必須使對象保持「可接受」狀態,無論該類型是什麼意思。在被移動的類型之外的任何東西都不應該負責維護對象的狀態。

而且,你要確保你打電話的舉動構造函數在父的舉動包含類型構造,而不是包含類型的舉動分配因爲你在你的例子

// move constructor calls move constructor of contained elements 
C (C<T>&& rhs) : mem_c(std::move(rhs.mem_c)) 
{ 
    // anything in here is using already-constructed data members 
} 

// move assignment calls move assignment of contained elements 
C & operator=(C<T>&& rhs) { 
    mem_c = std::move(rhs.mem_c); 
}