以c ++ 03对11返回值

时间:2012-12-06 22:36:23

标签: c++ c++11 lvalue rvalue

我花了几个小时关于 rvalue 和左值。这是我理解的

int main()
{
  //.....
  Foo foo = Bar1();
  foo = Bar2();
  //......
}  

Foo Bar1()
{
  //Do something including create foo
  return foo;
}

Foo& Bar2()
{
  //Do something including create foo
  return foo;
}

在c ++ 03下,Bar1()将复制返回对象(就在返回之前),然后返回复制对象的地址;执行一个即将被销毁的物品的浪费副本。 Bar2()将返回在函数中创建的对象。

在c ++ 11下,Bar1()Bar2()基本上是等价的(也等同于c ++ 03的Bar2())。

是吗?如果没有,请详细说明。

5 个答案:

答案 0 :(得分:6)

他们不一样。 Bar2()是两个标准的UB。您不能通过引用返回在堆栈上创建的对象。

在C ++ 03 Bar1()中可能会利用RVO并且不会复制任何内容。在C ++ 11中,Bar1()甚至会使用RVO,或者如果无法使用RVO,则会使用移动构造函数。

答案 1 :(得分:1)

rvalues和左值的概念并没有从旧的C ++变为C ++ 11。您所描述的“C ++ 03”应该是什么。在某些情况下,某些编译器优化可以减少不必要的副本数量(包括不必要的复制构造函数调用!),但除此之外它们是相同的。

更改的是C ++ 11引入了rvalue-reference(T&&)的概念。

有几篇文章你可以谷歌,例如在这里:

http://thbecker.net/articles/rvalue_references/section_01.html

答案 2 :(得分:1)

Bar2()不会在C ++ 2003或C ++ 2011中创建任何副本。对于Bar1(),在{+ C} 2003和C ++ 2011中都会创建foo的副本。使用rvalue引用仅适用于您实际拥有右值的情况,或者如果您的左值很快就会消失并且正在返回。

当然,该示例恰好是未定义的行为,因为返回的foo是正在初始化的foo。也就是说,似乎你的例子是因为没有说明foo返回时的意图而搞砸了。假设每个函数都有一个局部变量fooBar2()根据两个标准都是未定义的行为,Bar1()有些不同:

  • 如果有Foo的移动构造函数,C ++ 2011可能会使用移动构造函数,而C ++ 2003可能会使用复制构造函数。
  • 是否使用移动构造函数或复制构造函数取决于函数的其余部分和编译器:如果return中的所有Bar1()语句都返回foo,则构造一个额外的大多数编译器都会省略对象。

答案 3 :(得分:0)

  

Bar2()将返回在函数中创建的对象。

这显然是错的。 Bar2()会将引用返回给某个对象。 (注意:如果在Bar2())内的堆栈上创建了对象,那么它将是UB。

  

在c ++ 11下,Bar1()和Bar2()基本上是等价的(也等同于c ++ 03的Bar2())。

在C ++ 11下,意思是一样的。你真正感兴趣的是移动语义:

Foo Bar3()
{
  //Do something
  return std::move(foo);
}

这不会执行复制构造函数,而是执行一个移动构造函数 - 这应该会减少资源消耗。

答案 4 :(得分:0)

这篇文章对您有用:Want Speed? Pass by Value.

在C ++ 03中,Bar1()可能会复制对象(但这会被所谓的复制省略优化 - 请参阅链接)。

在C ++ 11中,基本上没有任何改变。允许编译器调用Foo的复制构造函数或Foo的移动构造函数或复制省略。但是,即使在C ++ 03中,副本也会被省略,Bar1()在C ++ 11和C ++ 03中也是如此。

Bar2()只返回一个引用,C ++ 11中没有什么不同。返回引用可能很关键。如果foo是本地值,则返回对已经销毁的变量的引用,永远不会返回。