2015-08-31 37 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;/*错误* /' –

相关问题