临时对象的引用绑定是否为未定义行为?成员引用生存期问询
问题1:将引用绑定到临时对象的成员是否属于未定义行为?
我猜你可能表述上有点小偏差,应该是“将引用绑定到临时对象的成员”?如果理解错了可以随时补充,咱们先基于这个最常见的场景解答:
这种情况本质上属于未定义行为,核心原因是:C++标准明确规定,只有当引用直接绑定到临时对象本身时,临时对象的生存期才会被延长到引用的生存期结束。但如果绑定的是临时对象的子对象(比如成员变量、数组元素),临时对象的生存期不会因为这个引用而延长——当包含临时对象的完整表达式执行完毕后,临时对象就会被销毁,此时引用就会悬空,后续使用这个引用的所有操作都是未定义行为。
举个直观的例子:
struct Foo { int x; }; const int& ref = Foo{}.x; // Foo临时对象在这一行结束后立刻销毁,ref变成悬空引用 // 后续任何访问ref的操作都是未定义行为
问题2:绑定临时对象成员的引用,原临时对象的生存期是否会延长?
虽然你没贴具体的代码片段,但结合你的描述,我猜你的代码大概是这样的:
struct Sphere { double radius; }; Sphere create_sphere() { return {5.0}; // 返回一个临时Sphere对象 } int main() { const double& r = create_sphere().radius; // 这里使用r是否安全? }
答案是Sphere临时对象的生存期不会被延长。当create_sphere()返回的临时对象所在的完整表达式(也就是const double& r = create_sphere().radius;这一行)执行完毕后,这个临时Sphere就会被销毁,此时r引用的是一个已经被销毁的对象的成员,后续访问r就是未定义行为——这大概率就是你遇到bug的根源。
至于为什么Clang和VS没发出警告?因为这种间接绑定临时对象成员的场景,属于编译器静态分析很难精准覆盖的情况。编译器无法百分百确定你后续是否会使用这个悬空引用,所以不会强制触发警告(不过有些编译器在开启更高等级的警告选项时,可能会提示类似“悬空引用”的问题,你可以试试打开-Wall -Wextra(Clang/GCC)或者/W4(VS))。
正确的写法:直接绑定临时对象本身
如果想让成员引用安全有效,你需要先把引用直接绑定到临时对象本身,这样就能延长它的生存期:
const Sphere& sphere = create_sphere(); // 临时Sphere的生存期被延长到sphere的生存期结束 const double& r = sphere.radius; // 此时r引用的是存活对象的成员,完全安全
内容的提问来源于stack exchange,提问作者Viktor Sehr

