为什么C ++ 11移动运算符(=)行为不同

时间:2015-08-31 20:38:35

标签: c++ c++11 move c++14 perfect-forwarding

我已经在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);
}

好吧我想也许不再需要= Move Operator了。但我尝试了一个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);有相同的行为吗?

3 个答案:

答案 0 :(得分:8)

语法

 DefaultConstructor testConstructor2 = something;

始终调用构造函数,因为对象testConstructor2尚不存在。 operator =只能在已经构造的对象的上下文中调用。

答案 1 :(得分: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=

答案 2 :(得分:2)

DefaultConstructor testConstructor2 = std::move(testConstructor);是施工,而非作业。它与C ++ 11之前的相同类型的代码中的复制构造与赋值完全类似。