C++临时对象生命周期结束后程序未崩溃的原因分析
为什么悬垂引用调用成员函数没有崩溃?
先看你的代码:
#include <iostream> using namespace std; struct Bar { inline void print() const { std::cout << "Bar" << std::endl; } }; struct Foo { Foo() : b{} {} // 创建临时对象 void print() const { b.print(); } // 正常运行,但我预期会崩溃 Bar&& b; }; int main() { Foo f; // 预期临时对象生命周期在此结束 f.print(); // 正常执行 - 输出"Bar" }
编译器给出的警告已经点出了核心问题:warning: a temporary bound to 'Foo::b' only persists until the constructor exits——你绑定到b上的临时Bar对象,在Foo构造函数执行完毕后就被销毁了,之后b就变成了悬垂引用,指向的内存已经不属于这个对象了。
那为什么调用b.print()没崩溃?这得从C++成员函数的调用逻辑说起:
Bar::print()是一个没有访问任何对象成员的非虚成员函数。- 非虚成员函数的调用本质上是编译器把对象地址作为隐式
this指针传递给函数。这里的this指针指向的是原临时对象占用的内存,但因为print()里没有读取或写入该对象的任何成员(只是输出固定字符串),所以即使内存已被释放,只要这块内存还没被其他数据覆盖,函数就能正常执行。
换句话说,你只是“碰巧”没触发错误——这属于C++里的未定义行为(Undefined Behavior):标准没有规定这种情况下程序必须崩溃,它可能正常运行、可能崩溃、可能输出乱码,甚至可能做任何奇怪的事情。
如果给Bar加个成员变量试试,比如:
struct Bar { std::string s = "Bar"; inline void print() const { std::cout << s << std::endl; } };
这时再运行,很大概率会崩溃或者输出乱码,因为print()需要访问this->s,而这块内存已经被销毁,内容是无效的。
总结一下:悬垂引用本身是严重的错误,只是你的测试场景刚好没触发崩溃,但绝对不能依赖这种行为——编译器警告已经明确告诉你问题了,一定要修复它(比如把Bar&& b改成Bar b,或者确保引用指向的对象生命周期足够长)。
内容的提问来源于stack exchange,提问作者Joseph D.
相关产品推荐
相关产品推荐

