【问题标题】:Rvalue reference: Why aren't rvalues implicitly moved?右值引用:为什么不隐式移动右值?
【发布时间】:2013-01-16 05:00:37
【问题描述】:

关于 C++ 右值引用 (http://www.artima.com/cppsource/rvalue.html) 的 Artima 文章中有一句话:这就是为什么在传递给基类时必须说 move(x) 而不仅仅是 x。这是移动语义的一个关键安全特性,旨在防止从某个命名变量意外移动两次。

我想不出这种双招可以执行的情况。你能举个例子吗?换句话说,如果T&& 的所有成员都是右值引用而不仅仅是引用,会出现什么问题?

【问题讨论】:

    标签: c++ c++11 rvalue-reference


    【解决方案1】:

    考虑这种情况:

    void foo(std::string x) {}
    void bar(std::string y) {}
    
    void test(std::string&& str)
    {
        // to be determined
    }
    

    我们想用str 调用foo,然后用str 调用bar,两者的值相同。最好的方法是:

    foo(str); // copy str to x
    bar(std::move(str)); // move str to y; we move it because we're done with it
    

    这样做是错误的:

    foo(std::move(str)); // move str to x
    bar(std::move(str)); // move str to y...er, except now it's empty
    

    因为在第一次移动之后,str 的值是未指定的。

    所以在右值引用的设计中,这种隐含的移动是不存在的。如果是这样,我们上面最好的方法就行不通了,因为第一次提到 str 会是 std::move(str)

    【讨论】:

      【解决方案2】:

      我的看法是,如果我们有一些右值引用 x:

      T&& x = ...;
      

      我们使用 x 作为参数调用了一些函数:

      f(x)
      

      我们需要以某种方式告诉 f 它是否会损坏 x(或“获得 x 的所有权”,或“是最后一个使用 x 的客户端”)。

      一种设计方法是限定每个调用:

      f(yours_now(x)) // ok to damage
      f(still_mine(x)) // dont damage
      

      并使不合格的调用非法。

      另一种方式是将一种方式设为默认方式:

      要么:

      f(yours_now(x)) // ok to damage
      f(x) // dont damage
      

      f(x) // ok to damage
      f(still_mine(x)) // dont damage
      

      因此,如果我们同意限定每次使用都过于庞大,我们应该默认使用一种方式,哪种方式最好?好吧,让我们看看在这两种情况下意外选择默认值的代价:

      在第一种情况下,损坏是可以的,但我们不小心说它不是。在这种情况下,我们会因为制作了不必要的副本而失去性能,但除此之外没什么大不了的。

      在第二种情况下,损坏对象是不行的,但我们不小心说它是。这可能会导致程序中难以检测到逻辑错误,因为 x 现在在 f 返回时处于损坏状态,但作者预计不会如此。

      所以选择第一种情况是因为它“更安全”。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-12-13
        • 2021-08-26
        • 2018-08-06
        • 1970-01-01
        • 2018-02-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多