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

Why does calling std::move on a const object call the copy constructor when passed to another object?

本文关键字:调用 一个对象 构造函数 复制 move 对象 const std 为什么      更新时间:2023-10-16

为什么在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方面进展如何。

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

显式delete函数并不意味着它不可用于重载解析,但如果它确实是重载解析选择的最可行的候选函数,则它是编译器错误。

结果是有意义的,因为移动构造是从源对象窃取资源从而改变它的操作,因此您不应该仅仅通过调用 std::move 来对const对象执行此操作。

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

#include <iostream>
struct Foo {
    Foo() = default;
    Foo(Foo &&) { std::cout << "Moven"; }
    Foo(Foo const&&) { std::cout << "Move constn"; }
    Foo(Foo const &) = delete;
};
int main() {
    Foo const x; Foo y(std::move(x)); 
}
相关文章: