为什么在const对象上调用std :: move会在传递给另一个对象时调用复制构造函数?

时间:2015-01-07 02:25:18

标签: c++ c++11 c++14

为什么在const对象上调用std :: move会在传递给另一个对象时调用复制构造函数?具体来说,代码

#include <iostream>

struct Foo {
    Foo() = default;
    Foo(Foo && x) { std::cout << "Move" << std::endl; }
    Foo(Foo const & x) = delete;
};

int main() {
    Foo const x; Foo y(std::move(x)); 
}

无法使用以下消息进行编译:

g++ -std=c++14 test07.cpp -o test07
test07.cpp: In function 'int main()':
test07.cpp:10:36: error: use of deleted function 'Foo::Foo(const Foo&)'
     Foo const x; Foo y(std::move(x)); 
                                    ^
test07.cpp:6:5: note: declared here
     Foo(Foo const & x) = delete;
     ^
Makefile:2: recipe for target 'all' failed
make: *** [all] Error 1

当然,我希望它失败,因为我们无法移动const值。同时,我不了解代码在尝试调用复制构造函数之前所采用的路径。这意味着,我知道std::move会将元素转换为x值,但在const之后,我不知道事情是如何进行的。

2 个答案:

答案 0 :(得分:38)

使用std::move参数调用T const的结果类型为T const&&,不能绑定到T&&参数。下一个最佳匹配是您的复制构造函数,它被删除,因此错误。

明确地delete一个函数并不意味着它不能用于重载解析,但如果它确实是重载决策选择的最可行的候选者,则它是编译器错误。

结果很有意义,因为移动构造是一种从源对象窃取资源的操作,从而使其变异,因此您不能仅通过调用{{1}来对const对象执行此操作}}

答案 1 :(得分:11)

std::move(x)的类型为Foo const&&,无法绑定到Foo&&。推理与T const&无法绑定到T&的推理相同。但是,您可以使用Foo const&&构造函数。很可能你不能真正移动相应对象的数据,但是,例如,在你的例子中没有数据,即下面的代码工作正常:

#include <iostream>

struct Foo {
    Foo() = default;
    Foo(Foo &&) { std::cout << "Move\n"; }
    Foo(Foo const&&) { std::cout << "Move const\n"; }
    Foo(Foo const &) = delete;
};

int main() {
    Foo const x; Foo y(std::move(x)); 
}