将返回Foo的函数的结果分配给const Foo&

时间:2009-07-28 20:30:30

标签: c++

我有一个返回Foo类型的对象的函数:

Foo getFoo();

我知道以下内容会编译并且会有效,但为什么我会这样做?

const Foo& myFoo = getFoo();

对我来说,以下内容更具可读性,并且不会强迫我记住C ++允许我为const引用分配r值:

const Foo myFoo = getFoo();

两者有什么区别?为什么我会在第二次使用第一个?为什么我会在第一个使用第二个?

4 个答案:

答案 0 :(得分:4)

我认为GotW #88会回答这个问题

答案 1 :(得分:4)

与流行的观点相反,无法保证将按值返回对象的函数的结果分配给const引用将导致比将对象分配给对象本身更少的副本。

将rvalue分配给const引用时,编译器可以通过两种方式之一绑定引用。它可以通过复制rvalue并将引用绑定到该临时值来创建一个新的临时值,或者它可以将引用直接绑定到rvalue本身。

如果编译器无法进行“显而易见”的优化以删除临时值而忽略复制构造函数的返回值getFoo,那么它有多大可能能够执行更有效的表单将rvalue绑定到const引用而不创建新的临时值?

使用const引用的一个原因是使函数对潜在的切片更加健壮。如果返回类型实际上是从Foo派生的类型,那么即使编译器确实从函数返回的rvalue中创建了一个临时对象,也可以保证不会切片分配给基类const引用。无论基类中的析构函数是否为虚拟,编译器还将生成对派生类析构函数的正确调用。这是因为创建的临时对象的类型基于所分配的表达式的类型,而不是基于正在初始化的引用的类型。

请注意,返回值的副本数量问题完全独立于返回值优化命名的返回值优化。这些优化指的是消除将返回表达式或命名局部变量的rvalue结果的副本复制到函数体内函数的返回值中。显然,在最好的情况下,可以进行返回值优化,并且可以消除返回值的临时值,从而不会对返回的对象执行复制。

答案 2 :(得分:1)

允许这种模式是有效的:

void foo(const SomeType &);

foo(SomeType(bar))

在这种情况下,构造一个临时SomeType并传递给foo。最有可能的事实是,您还可以在堆栈上对临时工具进行常量引用,这是用于在标准中定义此行为的措辞的副作用。请注意,正如评论中提到的那样,临时的生命周期被扩展为引用本身的生命周期。

答案 3 :(得分:0)

可能有以下几个原因:

如果你不想引用const对象怎么办? 例如,这不起作用:

    const Foo &myFoo = getFoo();
    myFoo.myfield = x;

或者,如果从getFoo()返回临时对象怎么办?这将警告将引用(或地址)返回到本地:

    const Foo &getFoo(void)
    {
       Foo localFoo();
       // do the things you want to localFoo
       return( localFoo );
    }

const Foo& myFoo = getFoo()的内部完全相同 Foo myFoo = getFoo()所以const ref返回的性能值的参数是无效的。我发现返回合理大小的对象没问题。

免责声明 - 我没有在gcc上尝试这些例子。您的里程可能会有所不同。