深返回时右值引用中断

Posted

技术标签:

【中文标题】深返回时右值引用中断【英文标题】:rvalue references break when deep-returning 【发布时间】:2011-01-07 20:22:19 【问题描述】:

我在从超过 1 的深度传递返回的右值引用时遇到了问题。

struct Data 
 std :: vector <int> data;
 Data () 
  data .push_back (1);
 ;

 Data (Data && d)
 : data (std :: move (d .data))
 
;

Data && foo () 
 Data d;
 return std :: move (d);


Data && bar () 
 return std :: move (foo ()); // Crashes in autogenerated code


Data && baz () 
 return foo (); // Crashes in Data move constructor.


Data && bop () 
 Data d = foo ();
    return std :: move (d); // Crashes in autogenerated code.


int main () 
 Data d_foo = foo (); // This is fine.
 Data d_bar = bar (); // Crash.
 Data d_bar = baz (); // Crash.
 Data d_bop = bop (); // Crash.

我认为 std::vector 正在被双重释放。我正在使用 g++ (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5

上面的代码对你有用吗?我做错了什么还是库或编译器中存在错误?

如果(天堂原谅)它是编译器(gcc 中还有其他已知的 C++0x 错误),有人可以告诉我是否有一种安全的方式来升级或修补 ubuntu 上的 gcc?我之前尝试过,但遇到了一堆不受支持的软件包。

非常感谢。

【问题讨论】:

你应该关注this video 的右值引用。 【参考方案1】:

从函数返回右值引用很少有意义(std::move 例外),因为引用可能绑定到临时对象或堆栈上的对象,就像你的情况一样,当你返回它时,对象就消失了.

编辑:

Data && foo () 
 Data d;
 return std :: move (d);

d 在超出范围时被销毁,因此您将返回悬空引用。

【讨论】:

作为后续,为了在这里利用右值引用,只需让函数按值返回。编译器将自动使用新的移动构造函数将数据移出而不是复制。 @templatetypedef -- 按值返回是对的,除了编译器会在诉诸移动对象之前尝试省略副本。【参考方案2】:

您不返回右值引用,而是返回一个值,然后调用者将其作为右值作为引用。你应该只有Data foo(),而不是Data&amp;&amp; foo()。这些作品中的任何一个都纯属巧合,因为它是未定义的行为。

【讨论】:

【参考方案3】:

您不能期望将&amp;&amp; 返回到本地对象有什么好处,就像返回一个常规引用​​/指向本地对象的指针一样。

您应该按值返回。在 C++03 下,允许编译器优化对复制构造函数的调用。在 C++0x 中,这意味着(如果无法优化复制 - 例如编译器在从不同分支返回不同对象时不管理它)将调用移动构造函数而不是复制构造函数(如果可用)从函数中获取值。

据我所知,移动语义应该在安全的地方自动启动,而右值引用参数类型允许您确定参数是否是右值(您可以显式移动的东西)。

【讨论】:

以上是关于深返回时右值引用中断的主要内容,如果未能解决你的问题,请参考以下文章

我应该通过右值引用返回一个右值引用参数吗?

C11新特性右值引用&&

C++11 中的左值引用和右值引用的区别

右值引用,移动语义,完美转发

右值引用的参数传递疑问(C++0x)

c++中的左值和右值,右值引用到底是啥?关于引用这一节看得很迷糊。