2016-12-12 34 views
2

关于此问题还有一次,但相关问题不回答我的问题。移动对象无移动构造函数

的标准是相当清楚的:

12.8复制和移动类对象,
§9
如果一个类X的定义不明确宣布此举的构造函数,一个会被隐式声明作为默认当且仅当
- X没有一个用户声明的拷贝构造函数,
- X没有一个用户声明的拷贝赋值运算符,
- X没有一个用户声明莫ve赋值运算符,
- X没有用户声明的析构函数,并且
- 移动构造函数不会被隐式定义为已删除。
[注意:当移动构造函数未被隐式声明或显式提供时,否则将调用移动构造函数的表达式可能会调用复制构造函数。 - 注完]

所以,注意到了“注”,在年底前,我预计这段代码失败编译(虽然我知道,那动人的应该退回到复印):

#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()
F()
Ç::〜C()

注意 “失踪” 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

+4

'cr'是r值**参考**,它尚未被任何构造函数消耗... –

+0

@ W.F。 - 哦,我的,请张贴这个答案。你非常正确。 (添加'c xx(std :: move(x));'而不是使用'f(c &&)'产生预期的行为 –

+0

这是一个nop问题XD – Stargateur

回答

6

您示例中的cr参数是一个r值参考。这里的参考词很重要。它的作用有点类似于我们在C++ 11之前在C++中知道的平面旧引用,它不会调用任何构造函数......它只是“指向”您传递的对象。 ..

要调用移动的构造函数(或做其他交换)并消耗参考,我们需要进一步转发参考例如如下:

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

您没有移动任何对象。

std::move实际上很混乱,因为它不会移动任何东西。只有移动构造函数或移动赋值操作符才能移动对象,std::move所做的只是将一个l值引用(&)投射到r值引用(&&)。

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

+0

这是一个非常好的解释,它完美地补充了接受的答案。 –