按值与右值参考返回

时间:2018-07-07 07:27:38

标签: c++ reference rvalue return-by-reference return-by-value

在回复question about returning temporaries 之后,我发现还有第二个回复,该回复略有不同。

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

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

2 个答案:

答案 0 :(得分:3)

主要区别在于,如果返回右值引用,则当将返回值绑定到引用时,临时对象的生存期将不会延长。

例如,

{{1}}

答案 1 :(得分: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上进行验证。

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

  1. AFAICT,您只能在一个新构造的对象上调用它,因此无论如何似乎没有什么意义。
  2. 由于它是从*this中移动出来的,因此它在原则上吞噬了新构造的对象,因此不应依赖返回的引用(仍然引用该对象)。
  3. li>
  4. 如@xskxzr所指出的那样,在步骤1中创建的临时生存期是无限的。

Bar& doThings()可以正常工作(并且实际上返回指向对象本身的指针,因此不会涉及任何复制或临时操作)。

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

Live demo