3

在回答有关返回临时工的问题后,我注意到第二个回答略有不同。

它不是按值返回,而是按右值引用返回。您能解释一下这些方法之间的区别以及它们的风险在哪里吗?

struct Bar
    {
    Bar& doThings() & {return *this;}

     // Returning rvalue reference
    Bar&& doThings() &&    {return std::move(*this);}

     // Alternative: Returning by value
    //Bar doThings() && {return std::move(*this);}

    std::unique_ptr<int> m_content; // A non-copyable type
    };
4

2 回答 2

3

一个主要区别是,如果返回右值引用,则当返回值绑定到引用时,临时对象的生命周期不会延长。

例如,

Bar&& rb = Bar{}.doThings();
use(rb); // not safe if returning rvalue reference, while safe if returning by value
于 2018-07-07T15:42:16.083 回答
0

我对此很感兴趣,所以我敲了一个小测试程序:

#include <memory>
#include <iostream>

struct Bar
{
    // Return by reference
    Bar& doThings() & { return *this; }

    // Return by rvalue reference
    Bar&& doThings() && { std::cout << "in Bar&& doThings, this=" << (void *) this << "\n"; return std::move (*this); }

    ~Bar () { std::cout << "Bar destroyed at " << (void *) this << "\n"; }

    int first;
    std::unique_ptr<int> m_content; // Make Bar a non-copyable type
};

int main ()
{
    std::cout << std::hex;
    Bar bar;
    std::cout << "bar is at " << &bar << "\n";
    Bar& bar_ref = bar.doThings ();
    std::cout << "bar_ref refers to " << &bar_ref.first << "\n\n";
    Bar&& bar_rvalue_ref = Bar ().doThings ();
    std::cout << "bar_rvalue_ref refers to " << &bar_rvalue_ref.first << "\n\n";
}

输出:

bar is at 0x7ffdc10846f0
bar_ref refers to 0x7ffdc10846f0

in Bar&& doThings, this=0x7ffdc1084700
Bar destroyed at 0x7ffdc1084700
bar_rvalue_ref refers to 0x7ffdc1084700

Bar destroyed at 0x7ffdc10846f0

所以这告诉我们,这两种形式都不会doThings()产生临时性。您也可以在Godbolt验证这一点。

那么,看看 aswritten 的实现,Bar会给我们留下什么?好吧,我个人根本看不到任何目的,Bar&& doThings()因为:

  1. AFAICT,您只能在新构造的对象上调用它,所以无论如何它似乎没什么意义。
  2. 因为它从移动*this,所以原则上它会吃掉那个新构造的对象,所以返回的引用(仍然引用它)是不可靠的。
  3. 正如@xskxzr 已经指出的那样,在步骤 1 中创建的临时对象的生命周期非常短。

然而,Bar& doThings()工作得很好(实际上,返回一个指向对象本身的指针,因此不会涉及复制或临时对象)。

我确定我错过了一些重要的事情,所以我很想听听人们对此的反应。当然,通过右值引用返回是有一些目的的,也许在更复杂的情况下。谢谢。

现场演示

于 2018-07-07T16:59:01.290 回答