【问题标题】:Why does calling std::move on a const object call the copy constructor when passed to another object?为什么在传递给另一个对象时调用 const 对象上的 std::move 会调用复制构造函数?
【发布时间】:2015-03-04 19:42: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 的事情如何进行。

【问题讨论】:

  • 被移动对象的constness没有改变,Foo const&amp;&amp;不能绑定到Foo&amp;&amp;所以编译器尝试访问复制构造函数,因为它被删除了失败。跨度>
  • 我不是移动运算符方面的专家,但也许你可以在 const 值上调用 move,但其结果只能被复制构造函数接受,因此编译器决定调用它。
  • "意思是,我知道 std::move 将元素转换为 x 值" 实际上,它没有。它返回对项目的右值引用。
  • @BenVoigt,有什么区别? [basic.lval] "调用返回类型为对对象类型的右值引用的函数的结果是一个xvalue。"
  • @BenVoigt std::move(v) 的结果是转换表达式 v 的结果(这是一个左值和一个对象,但不是左值引用,因为表达式没有引用类型, [expr]/5) 输入 Foo&amp;&amp; (这是一个 xvalue)...我认为说它不会将 v 转换为 xvalue 是不必要的迂腐,或者完全是错误的。

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


【解决方案1】:

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

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

结果是有道理的,因为移动构造是一个从源对象窃取资源的操作,从而改变它,所以你不应该仅仅通过调用 const 来对 const 对象执行此操作@。

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-21
      • 2012-08-15
      • 2018-10-26
      • 2019-01-13
      • 2013-05-19
      • 2014-12-31
      • 1970-01-01
      • 2021-02-26
      相关资源
      最近更新 更多