与const引用关联的临时对象的生命周期(方法链接)

αλε*_*λυτ 9 c++ reference lifetime

考虑以下代码snipet:

#include <iostream>

struct S {
    ~S() { std::cout << "dtor\n"; }
    const S& f(int i) const { std::cout << i << "\n"; return *this; }
};

int main() {
    const S& s = S(); 
    s.f(2);
}
Run Code Online (Sandbox Code Playgroud)

输出:

2
dtor
Run Code Online (Sandbox Code Playgroud)

即对象的生命周期通过引用扩展,这在Herb的文章中有所解释.

但是,如果我们只更改一行代码并写入:

const S& s = S().f(1);
Run Code Online (Sandbox Code Playgroud)

f(2)对已经被摧毁的物体的召唤:

输出:

1
dtor
2
Run Code Online (Sandbox Code Playgroud)

为什么会这样?是f()的返回值不是一个正确的类型'暂时性’的?

Ton*_*roy 4

当你这样编写一个函数时......

const S& f(int i) const { std::cout << i << "\n"; return *this; }
Run Code Online (Sandbox Code Playgroud)

...您指示编译器返回 aconst S&并且您负责确保引用的对象具有适合调用者使用的生命周期。(“确保”可能构成记录与您的设计正常配合的客户端使用情况。)

通常,通过将代码典型地分离为标头和实现文件,f(int) const调用代码甚至看不到实现,在这种情况下,编译器无法了解S可能返回的引用,也无法了解该引用是否S是临时的。是否需要延长寿命没有依据。

除了明显的选项(例如,信任客户端编写安全代码、按值返回或智能指针)之外,值得了解一个更晦涩的选项......

const S& f(int i) const & { ...; return *this; }
const S f(int i) const && { ...; return *this; }
Run Code Online (Sandbox Code Playgroud)

和紧接在函数体重载之前,如果可移动则使用版本,否则&使用版本。这样,将 a 绑定到在过期对象上调用的人将绑定到该对象的新副本,并根据本地引用延长生命周期,而当对象尚未过期时,引用将指向原始对象(仍然不能保证与参考一样长的寿命 - 需要一些谨慎)。&&f&&*this&const &f(...)constconst