You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C风格指针值异常但智能指针值正确的C++代码问题分析

问题分析:Foo类指针失效而Bar类正常的原因

咱们直接戳破核心——Foo里的指针指向了已经被销毁的临时对象内存,属于典型的悬空指针问题;而Bar是把值复制到了自己管理的独立内存中,所以能正常工作。

一、Foo类的坑:悬空指针是怎么来的?

先看Foo的构造函数代码:

Foo(std::vector<int> vec) {
 a = &(vec.front());
}

这里的vec是按值传递的参数——也就是说,当你调用Foo foo(vec);时,程序会创建一个原vec的拷贝,这个拷贝只在Foo的构造函数执行期间存在。

一旦构造函数执行完毕,这个临时的拷贝vector就会被销毁,它所管理的内存(包括里面存储的int元素)也会被系统回收。而你让foo.a指向的,正是这个临时vector里第一个元素的地址。现在这个地址对应的内存已经不属于你的程序了,这就是悬空指针。

当你后续解引用*foo.a时,行为是完全未定义的——输出0只是碰巧的结果,它也可能输出随机垃圾值,甚至直接导致程序崩溃。

二、Bar类为什么能正常输出42?

再看Bar的构造函数:

Bar(std::vector<int> vec) {
 a = std::make_unique<int>(vec.front());
}

std::make_unique<int>(vec.front())做了两件关键的事:

  1. 先读取临时拷贝vector里第一个元素的值(也就是42)
  2. 在堆上分配一块全新的内存,把42复制进去,然后让unique_ptr接管这块内存的生命周期。

哪怕构造函数结束后临时vector被销毁,也完全不影响——因为Bar的a指向的是独立的堆内存,里面存的是42的副本,和原来的vector没有任何关联。所以后续解引用*bar.a时,自然能拿到正确的42。

三、如何修复Foo类?

如果想让Foo也能正确工作,有几个可行的思路:

  • 把构造函数参数改成引用传递,避免创建临时拷贝:Foo(std::vector<int>& vec),这样vec就是原vector的引用,只要原vector的生命周期比Foo对象长,指针就会一直有效。
  • 放弃指针,直接存储值:把int* a;改成int a;,构造函数里直接赋值a = vec.front();,彻底避开指针问题。
  • 如果必须用指针,也可以改用智能指针管理,但这个场景下其实没必要,前两种方案更简单直接。

内容的提问来源于stack exchange,提问作者justicecurcian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 03:35:19