临时寿命延长

19

标准的第12.2.5节规定:

函数调用中引用参数的临时绑定(5.2.2)持续到包含该调用的完整表达式完成为止。函数返回语句中返回值的临时绑定(6.6.3)持续到函数退出为止。在所有这些情况下,在初始化引用的表达式求值期间创建的临时值(除了与引用绑定的那个临时值)将在创建它们的完整表达式结束时以相反的顺序销毁。

我正在尝试理解以下代码:

#include <iostream>

const int& foo(const int& fooRef)
{
    return fooRef;
}                                        // #0

int main (void)
{
    const int& numberRef = foo(5);     // #1
    std::cout << numberRef;            // #2
    return 0;
}

在代码的第一行创建了一个临时对象并将其绑定到fooRef上,fooRef在代码的第0行被销毁。但由于生命周期延长不是可传递的,所以我认为这里应该销毁临时对象。

问题:

  1. 直到函数退出是什么意思?它是否意味着直到执行完成

  2. 为什么程序输出5?在第#2行,临时对象还存在吗?

  3. 我该如何解释标准引用以弄清楚这个例子的工作原理?

请提供逐步详细的解释,并引用与标准相关的内容。谢谢!

P.S. 一个已接受的答案here也说明这段代码是有问题的,但我不明白为什么会得到这样的程序输出。


当我使用G++ 9.3.0编译您的代码时,输出为5。当我使用-O2标志进行编译时,实际上输出为0。添加选项-Wall会警告使用未初始化的值。相反,使用clang++始终会打印5且没有警告消息,不受使用的编译器选项的影响。但不要依赖于这种行为! - Kai Petzke
2个回答

10

Until the function exits是什么意思?它是否意味着函数执行完成后才退出?

是的。

为什么我会得到一个5的输出。第2行还存在一个临时对象吗?

对未绑定到活动对象的引用进行解引用是未定义行为,因此您可能会得到542或其他任何结果(包括崩溃)。您不能对具有未定义行为的程序进行任何期望。

如何理解标准引文以弄清楚此示例的工作原理?

与您已经做过的类似。临时对象与函数参数fooRef绑定,在从函数返回时被销毁。由于该临时对象绑定到返回值,因此该对象在函数返回时停止存在。稍后,您正在解引用悬挂的引用,这会导致UB。


2
  1. 意味着直到闭合括号,即 }

  2. 您引发了UB,您的引用是悬垂的。

尝试修改您的代码,并查看它打印出什么。它可能会打印出6,因为它是堆栈中最后一个数字。或者尝试传递一个std::string,您可能会遇到崩溃。

int main (void)
{
    const int& numberRef = foo(5);  
    foo(6);
    std::cout << numberRef;
    return 0;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接