为什么c++ 11的移动操作符(=)的行为不同?

Why is the C++11 move operator (=) behavior different

本文关键字:c++ 移动 操作符 为什么      更新时间:2023-10-16

我已经在c++ 11中测试了move Semantic。我写了一个带有move构造函数的类。

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;
};

我写了一个使用move语义的main函数。我理解在移动语义中发生了什么,它是一个伟大的工具。但有些行为我无法解释。当我调用主函数DefaultConstructor testConstructor2 = std::move(testConstructor);时,DefaultConstructor& operator=(DefaultConstructor&& def)应该被调用。但是Visual Studio 2015调用move构造函数。

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运算符不再是必要的了。但我尝试了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);的调用不应该有相同的行为吗?

语法

 DefaultConstructor testConstructor2 = something;

总是调用构造函数,因为对象testConstructor2还不存在。Operator =只能在已经构造的对象上下文中调用

This:

T foo = bar;

称为复制初始化。它通常(但不总是)等同于:

T foo(bar);

的区别在于,后者是对T的构造函数的直接函数调用,而前者试图构造一个从decltype(bar)T的隐式转换序列。因此,存在直接初始化成功而复制初始化失败的情况。不管怎样,初始化就是初始化:它是构造函数调用,而不是赋值调用。

在我们的例子中,这两行是完全等价的:

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

它们都不调用DefaultConstructor::operator=

DefaultConstructor testConstructor2 = std::move(testConstructor);是构造,不是赋值。这完全类似于c++ 11之前的相同类型代码中的复制构造与赋值。