在没有移动构造函数的情况下移动对象

Move object without a move constructor

再说一遍,相关问题没有回答我的问题

标准很明确:

12.8 Copying and moving class objects,
§9
If the definition of a class X does not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if
— X does not have a user-declared copy constructor,
— X does not have a user-declared copy assignment operator,
— X does not have a user-declared move assignment operator,
— X does not have a user-declared destructor, and
— the move constructor would not be implicitly defined as deleted.
[ Note: When the move constructor is not implicitly declared or explicitly supplied, expressions that otherwise would have invoked the move constructor may instead invoke a copy constructor. — end note ]

所以,在注意到最后的 "Note" 之前,我预计这段代码会编译失败(虽然我知道,移动 应该 回退到复制) :

#include <iostream>
using std::cout;
class c
{
public:
    c() { cout << "c::c()\n"; }
    c( std::initializer_list< int > ) { cout << "c::c( std::initializer_list )\n"; };

    c( const c& ) { cout << "c::c( const c& )\n"; }
    c& operator=( const c& ) { cout << "c& c::operator=( const c& )\n"; return *this; }

    ~c() { cout << "c::~c()\n"; }

    void f() {}
};

void f( c&& cr ) { cout << "f()\n"; cr.f(); }

int main()
{
    c x;
    f( std::move( x ) );

    return 0;
}

然后看到最后的注释,还是很惊讶,上面的代码输出:

c::c()
f()
c::~c()

注意 "missing" c::c( const c& )。然后我添加了

c( c&& ) = delete;
c& operator=( c&& ) = delete;

结果还是一样

我在这里想念什么?


$ g++ --version
g++ (Ubuntu 5.4.0-6ubuntu1~16.04.2) 5.4.0 20160609

编译器标志:-s -O0 -march=native -pthread -std=c++11 -Wall -Wextra -DNDEBUG.

您没有移动任何对象。

std::move其实挺迷惑的,因为它什么都没动。只有移动构造函数或移动赋值运算符可以移动对象,std::move 所做的只是将左值引用 (&) 转换为右值引用 (&&)。

移动构造函数或移动赋值运算符可以绑定到 r-value-refernce(&&) 并窃取对象内容。

您的示例中的 cr 参数是右值 reference。参考词在这里很重要。它的行为有点类似于我们从 c++ 中知道的平面旧引用,在 c++11 出现在游戏中之前,就它不调用任何构造函数而言......它只是 "pointing" 到你的对象通过...

要调用移动构造函数(或进行其他交换)并使用引用,我们需要进一步转发引用,例如如下:

void f( c&& cr ) {
   c cr2(std::move(cr));
}