C++使用指针取值异常、直接返回值正常的原因是什么?
问题原因分析
这是典型的悬空指针(野指针)触发的未定义行为,具体原因拆解如下:
1. 核心触发点
首先看A类的b()成员函数定义:
B b() { return b_; }
该接口是按值返回,也就是说每次调用a.b()时,都会生成一个B类型的临时对象,它是a内部b_成员的拷贝,生命周期仅维持到当前完整表达式执行结束。
2. 第一种写法错误的完整过程
第一种循环的执行逻辑:
for (auto it : *(a.b().mutable_c()))
- 第一步:调用
a.b()生成一个临时B对象 - 第二步:调用该临时对象的
mutable_c(),拿到的是临时对象内部c_成员的内存地址 - 第三步:
a.b().mutable_c()表达式执行完成,临时B对象被销毁回收,其内部c_成员的内存也随之释放 - 第四步:范围for循环拿着已经失效的指针访问已释放的内存,读取到的都是脏数据,属于未定义行为。你看到的0、异常小浮点数、偶尔看似正确的输出,都是内存未被覆盖时的巧合结果,没有任何可靠性,甚至可能直接触发程序崩溃。
3. 第二种写法正确的原因
第二种循环的逻辑:
for (auto it : a.b().c())
这里a.b().c()是按值返回vector<C>,相当于直接把临时B对象内的c_拷贝了一份出来,这个拷贝得到的vector生命周期会覆盖整个循环过程,内存访问完全合法,所以结果正确。
修复方案
如果要让第一种指针访问的写法可用,只需要把A类的b()接口修改为返回引用,避免生成临时对象即可:
// 修改A类的b()接口 B& b() { return b_; } // 只读场景可加const修饰 const B& b() const { return b_; }
修改后a.b()返回的是a内部原生b_成员的引用,生命周期和a一致,拿到的mutable_c()指针不会悬空,遍历结果就正常了。
内容的提问来源于stack exchange,提问作者jiang123456
相关产品推荐
相关产品推荐

