创建对象,局部变量与右值引用

Posted

技术标签:

【中文标题】创建对象,局部变量与右值引用【英文标题】:Creating an object, local variable vs rvalue reference 【发布时间】:2016-09-07 12:38:08 【问题描述】:

在创建对象时使用 r 值引用有什么好处,否则它会在普通的局部变量中?

Foo&& cn = Foo();
cn.m_flag = 1;
bar.m_foo = std::move(cn);
//cn is not used again

Foo cn;
cn.m_flag = 1;
bar.m_foo = std::move(cn); //Is it ok to move a non rvalue reference?
//cn is not used again

在第一个代码sn-p中,显然不会有任何副本,但我猜第二个代码编译会优化副本?

同样在第一个sn-p中,对象实际存储在内存中的什么位置(在第二个中它存储在封闭函数的堆栈帧中)?

【问题讨论】:

你的第一部分甚至不应该编译。第二部分完全符合您的要求。 std::move 使 cn 成为右值,然后将其移动到 m_foo (假设未删除移动运算符等)。 @Hayt,为什么不能编译?据我了解,将临时值分配给 r 值 ref 可以延长临时值的寿命(如果它是普通引用,那么是的,它不会编译) 嗯,好的。只是从未见过有人以这种方式编码(这并不是真正必要的)。但是仍然移动主要是为了将非右值对象变成右值。 【参考方案1】:

这些代码片段大多是等价的。这个:

Foo&& rf = Foo();

将临时对象绑定到引用,从而将临时对象的生命周期延长到引用的生命周期。 Foo 只会在 rf 超出范围时被销毁。这与您得到的行为相同:

Foo f;

除了在后一个示例中 f 是默认初始化的,但在前一个示例中 rf 是值初始化的。对于某些类型,两者是等价的。对于其他人,他们不是。如果您改为写Foo f,那么这种差异就会消失。

剩下的一个区别与复制省略有关:

Foo give_a_foo_rv() 
    Foo&& rf = Foo();
    return rf;


Foo give_a_foo() 
    Foo f;
    return f;

第一个例子中不允许执行RVO,因为rfgive_a_foo_rv()的返回类型不一样。此外,rf 甚至不会自动移入返回类型,因为它不是对象,所以它没有自动存储持续时间,所以这是一个额外的副本(直到 C++20,它是一个额外的移动) :

Foo f = give_a_foo_rv(); // a copy happens here!
Foo g = give_a_foo();    // no move or copy

显然不会有任何副本

这完全取决于移动 Foo 的实际作用。如果Foo 看起来像:

struct Foo 
    Foo() = default;
    Foo(Foo const& ) = default;
    Foo& operator=(Foo const& ) = default;

    // some members
;

然后移动 Foo 仍然会复制。


是的,在第二个例子中std::move(f) 是完全可以的。您不需要从它的Tmove 的右值引用类型的对象。这将严重限制移动的实用性。

【讨论】:

以上是关于创建对象,局部变量与右值引用的主要内容,如果未能解决你的问题,请参考以下文章

左值引用与右值引用

左值引用与右值引用

左值引用与右值引用

左值引用与右值引用

左值引用与右值引用

左值引用与右值引用