局部对象地址在函数返回后失效,因其存于栈上且生命周期限于函数作用域;返回其地址将导致悬垂指针和未定义行为。

局部对象的地址在函数返回后就失效了
因为局部对象存放在栈上,它的生命周期严格绑定在函数作用域内。函数返回时,栈帧被弹出,对应内存区域不再受保护——哪怕你没显式清零,那块地址也随时可能被后续函数调用覆盖。此时若还持有该地址(比如返回 &tmp),就是典型的悬垂指针(dangling pointer),解引用会触发未定义行为,常见现象包括程序崩溃、随机值、或看似“正常”但不可靠的结果。
return &local_obj 编译器通常不报错但绝不安全
编译器一般只警告(如 GCC 的 -Wreturn-local-addr),不会阻止编译,因为它无法 100% 判定所有间接引用场景。但只要出现以下任一情况,就等于踩雷:
- 函数返回的是局部变量、形参、或任何在函数体内用非
static方式定义的对象的地址 - 哪怕加了
const修饰(const Test*)也无效,地址本身已失效 - 用
std::addressof或强制类型转换绕过编译器检查,问题照旧
想长期保存对象数据?换这几种方式
核心原则:别留栈地址,改留“活得久”的东西。
- 返回对象本身(
Test GetObject(...)):触发拷贝或移动,调用者获得一份独立副本 - 返回
std::shared_ptr<test></test>或std::unique_ptr<test></test>:对象分配在堆上,生命周期由智能指针管理 - 用
static Test tmp局部静态对象:地址稳定,但注意它是全局共享的,多线程需同步,且每次调用都复用同一实例 - 让调用方传入存储位置(如输出参数
Test& out):把构造责任交给外部,避免栈逃逸
容易被忽略的隐含陷阱
有些写法看着“没定义局部变量”,其实照样危险:
-
return &(Test{42}):临时对象是右值,生命周期只到完整表达式结束,函数返回前就销毁了 -
auto p = &some_local; return p;:哪怕中间赋给变量,地址来源不变,依然悬垂 - 调试时发现“还能读到原值”:那是栈内存尚未被覆盖的巧合,不是安全依据
真正决定安全与否的,从来不是“现在能不能读”,而是“标准是否保证这块内存归你管”。局部栈对象的答案永远是否定的。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











