2015-08-31 40 views
2

我已經測試了C++ 11中的移動語義。我用移動構造函數寫了一個類。爲什麼C++ 11移動運算符(=)的行爲不同

class DefaultConstructor 
{ 
public: 
    DefaultConstructor(std::vector<int> test) : 
     m_vec(std::forward<std::vector<int>>(test)) 
    { 

    }; 

    DefaultConstructor(DefaultConstructor &&def) : 
     m_vec(std::forward<std::vector<int>>(def.m_vec)) 
    { 
    } 

    DefaultConstructor& operator=(DefaultConstructor&& def) { 
     m_vec = std::move(def.m_vec); 
     return *this; 
    } 

    DefaultConstructor& operator=(const DefaultConstructor&) = delete; 
    DefaultConstructor(DefaultConstructor &) = delete; 

    std::vector<int> m_vec; 
}; 

我寫了一個使用移動語義的主函數。我明白移動語義中發生了什麼,它是一個很好的工具。但是有一些行爲對我來說是無法解釋的。當我呼叫DefaultConstructor testConstructor2 = std::move(testConstructor);的主要功能時,應該調用DefaultConstructor& operator=(DefaultConstructor&& def)。但Visual Studio 2015調用移動構造函數。

int main() 
{ 
    std::vector<int> test = { 1, 2, 3, 4, 5 }; 
    DefaultConstructor testConstructor(std::move(test)); 

    DefaultConstructor testConstructor2 = std::move(testConstructor); 
    DefaultConstructor &testConstructor3 = DefaultConstructor({ 6, 7, 8, 9 }); 
    DefaultConstructor testConstructor4 = std::move(testConstructor3); 
    swapMove(testConstructor, testConstructor2); 
} 

好吧,我想也許=移動運算符不再是必要的。但我嘗試了一個SwapMove函數。這個函數調用= move操作符。

template<typename T> 
void swapMove(T &a, T &b) 
{ 
    T tmp(std::move(a)); 
    a = std::move(b); 
    b = std::move(tmp); 
} 

有人可以解釋這兩個電話之間的區別究竟是什麼?不應該是電話a = std::move(b);DefaultConstructor testConstructor2 = std::move(testConstructor);有相同的行爲?

+8

'DefaultConstructor testConstructor2 = std :: move(testConstructor);'是初始化,不是賦值。 –

+0

事先分別聲明'testConstructor2',例如'DefaultConstructor testConstructor2({});' –

+0

Jonatha Potter看起來像這就是答案。謝謝。 – PeterNL

回答

8

語法

DefaultConstructor testConstructor2 = something; 

總是調用構造函數,因爲對象testConstructor2還不存在。 operator =只能在已經構造的對象的上下文中調用。

2

DefaultConstructor testConstructor2 = std::move(testConstructor);是施工,而不是轉讓。這與在C++ 11之前的代碼中複製構造和賦值完全類似。

6

此:

T foo = bar; 

被稱爲copy-initialization。這是典型的,但並不總是等同於:

T foo(bar); 

所不同的是,後者是直接函數調用T的構造函數,而前者試圖構建的隱式轉換序列從decltype(bar)T。因此有直接初始化成功但複製初始化失敗的情況。無論哪種方式,初始化都是初始化:它是一個構造函數調用,而不是一個賦值調用。

在我們的情況下,雖然,這兩條線是完全等價的:

DefaultConstructor testConstructor2 = std::move(testConstructor); 
DefaultConstructor testConstructor2{std::move(testConstructor)}; 

而其中沒有一個叫DefaultConstructor::operator=

+1

出於好奇,什麼時候'T foo = bar;'不等於T foo(bar)'? –

+3

@PCLuddite當您需要多次轉換時。例如:'struct A {A(int){}}; struct B {B(A){}};'鑑於此,'B b(4);'成功,但B b = 4;'不會。 – Barry

+2

@PCLuddite另外,當你有一個更好匹配的'explicit'構造函數(或者唯一可能的匹配,這會使'='情況出錯)。 'struct A {explicit A(bool){/ *#1 * /} A(int){/ *#2 * /}}; A =真;/*致電#2 */A b(假);/*調用#1 * /'並且當所討論的類不可複製/移動時:'struct B {B(B &&)= delete; B(int){}}; B b(1);/* OK */B b2 = 1;/*錯誤* /' –

相關問題