返回值是否意味着额外的副本和额外的开销? C ++

时间:2014-04-21 11:00:28

标签: c++ constructor return-by-value

请考虑以下事项:

class Foo { ... };

Foo rbv();

void caller()
{
  Foo x = rbv(); ← the return-value of rbv() goes into x
  ...
}

Foo rbv()
{
  ...
  return Foo(42, 73); ← suppose Foo has a ctor Foo::Foo(int a, int b)
}

将构造多少个Foo类型的对象?

2 个答案:

答案 0 :(得分:3)

可能。

在C ++ 11中,如果值具有移动构造函数,则通过移动而不是复制来返回值。这比复制更有效。

在某些情况下 - 例如返回本地变量或临时变量(如此处所示) - 移动或复制可以省略。该值直接创建到调用者的堆栈帧中,因此在返回时不需要移动或复制它。喜欢首字母缩略词的人有时称之为(N)RVO - (命名)返回值优化。

同样,也可以省略从临时返回值到x的复制或移动。

任何体面的编译器都会实现此优化,因此您的代码应该只创建一个Foo。您可以通过使析构函数打印一条消息来验证这一点,并观察它只执行一次:http://ideone.com/xydJqY。如果禁用优化,则最多可能有三个对象。

答案 1 :(得分:1)

最多可能有两个副本:一个从临时Foo(42, 73)到函数的返回值,另一个从函数的返回值变为x。但是,这两个副本都有资格进行复制,不允许复制,而是直接在目的地构建对象,相当于Foo x(42, 73);

您可以控制编译器利用复制省略的程度;例如,在GCC中,您可以使用-fno-elide-constructors来获取所有两份副本。