引用初始化 - 临时绑定到返回值

问题描述

在 cppreference.com (Lifetime of a temporary) 上的一篇关于引用初始化的文章中,它说:

在 return 语句中临时绑定到函数的返回值不会被扩展:它会在 return 表达式的末尾立即销毁。这样的函数总是返回一个悬空引用。

此摘录解决了通过将引用绑定到临时文件来延长其生命周期的例外情况。他们实际上是什么意思?我想过类似的事情

#include <iostream>

int&& func()
{
    return 42;
}

int main()
{
    int&& foo = func();
    std::cout << foo << std::endl;

    return 0;
}

所以 foo 应该引用临时 42。根据摘录,这应该是一个悬空引用 - 但它打印 42 而不是一些随机值,所以它工作得很好。

我确定我在这里弄错了,如果有人能解决我的困惑,我将不胜感激。

解决方法

你的例子很好,但你的编译器不是。

临时对象通常是文字值、函数返回值,但也是使用语法“class_name(constructor_arguments)”传递给函数的对象。例如,在将 lambda 表达式引入 C++ 之前,要对事物进行排序,可以定义一些带有重载 X 的结构体 operator(),然后进行如下调用:

std::sort(v.begin(),v.end(),X());

在这种情况下,您希望使用 X() 构造的临时文件的生命周期将在结束指令的分号处结束。

如果你调用一个需要常量引用的函数,比如说,void f(const int & n),带有临时性,例如f(2),编译器创建一个临时 int,用 2 初始化它,并将对这个临时的引用传递给函数。您希望此临时文件以 f(2); 中的分号结束其生命周期。

现在考虑:

int && ref = 2;
std::cout << ref;

此代码完全有效。但是请注意,这里编译器还创建了一个类型为 int 的临时对象,并使用 2 对其进行初始化。这是 ref 绑定到的临时对象。但是,如果临时文件的生命周期仅限于它在其中创建的指令,并以标记指令结束的分号结束,那么下一条指令将是一场灾难,因为 cout 将使用悬空引用。因此,对上述临时变量的引用是相当不切实际的。这就是“临时文件生命周期的延长”所需要的。我怀疑编译器在看到类似 int && ref = 2 的内容时被允许将其转换为这样的内容

int tmp = 2;
int && ref = std::move(tmp);
std::cout << ref; // equivalent to std::cout << tmp;

如果没有生命周期扩展,这可能看起来像这样:

{
 int tmp = 2;
 int && ref = std::move(tmp);
}
std::cout << ref; // what is ref? 

在 return 语句中做这样的把戏是没有意义的。没有合理、安全的方法来延长函数局部对象的生命周期。

顺便说一句。大多数现代编译器都会发出警告并减少您的功能

int&& func()
{
    return 42;
}

int&& func()
{
    return nullptr;
}

在任何试图取消引用返回值时立即出现段错误。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...