为何指向栈上vector元素的shared_ptr在内存释放后仍可访问
问题解答
首先明确结论:你的代码属于未定义行为,shared_ptr完全没有延长局部变量vec的生命周期,能访问对应内存只是内存释放后未被立即回收覆写的偶然现象。
原因拆解
- 局部变量
std::vector<float> vec是栈上分配的对象,test()函数执行结束返回时,vec的生命周期就已经终止,其析构函数会自动释放内部存储float元素的堆内存,将这块内存标记为可重新分配状态。 - 你构造
shared_ptr时传入了空lambda删除器[](void* ptr){},仅代表shared_ptr自身的引用计数归零时不会主动释放指向的内存,并不代表shared_ptr会接管vec的生命周期:栈对象的生命周期由编译器静态管理,和堆上分配的智能指针引用计数没有关联。 - 你能成功读写内存只是临时现象:内存被释放后,操作系统/内存分配器不会立即擦除内存内容或禁止访问,只要这块内存还没有被其他程序逻辑申请使用,原有数据就会暂时残留,写入操作也暂时不会触发异常。你观测到的
第0位变成0、第1位写入9生效,完全是当前运行环境下内存分配逻辑的偶然结果,换编译选项、换操作系统、甚至同环境多次运行都可能出现完全不同的结果,比如程序崩溃、读到随机垃圾值等。
正确实现方式
如果需要让shared_ptr延长vector内存的生命周期,应该使用shared_ptr的别名构造函数,绑定vector本身的引用计数:
std::shared_ptr<float> test() { auto vec_shared = std::make_shared<std::vector<float>>(10); (*vec_shared)[0] = 10.1; (*vec_shared)[1] = 5.0; // 别名构造:shared_ptr指向元素,但持有整个vector的引用计数 std::shared_ptr<float> p_shared(vec_shared, &(*vec_shared)[0]); std::cout<<"Get value 0th: "<<p_shared.get()[0]<<" , 1st: "<<p_shared.get()[1]<< std::endl; return p_shared; }
这种场景下vec_shared的引用计数会被返回的p_shared持有,整个vector的生命周期会随p_shared延长,不会出现悬空指针问题。
内容的提问来源于stack exchange,提问作者Zack
相关产品推荐
相关产品推荐

