shared_ptr不能直接管理裸指针数组,因默认用delete而非delete[]释放,导致析构不全和内存泄漏;应显式传删除器或改用vector/array。

shared_ptr 为什么不能直接管理裸指针数组
因为 shared_ptr 默认用 delete 释放内存,而数组必须用 delete[];用错会导致未定义行为——对象析构不全、内存没真正释放,表面看没报错,实则已泄漏。
- 错误写法:
shared_ptr<int> p(new int[10]);</int>→ 只调delete,不调delete[] - 正确写法:显式传入删除器,
shared_ptr<int> p(new int[10], [](int* ptr) { delete[] ptr; });</int> - 更稳妥方案:改用
std::vector或std::array,它们自己管内存,不用手动配删除器
循环引用导致 shared_ptr 永远不释放
两个 shared_ptr 互相持有对方所管理的对象(比如父子节点、观察者/被观察者),引用计数永远 ≥1,对象无法析构——这是最隐蔽的泄漏源。
- 典型现象:对象的析构函数从不执行,
valgrind报“still reachable”或“definitely lost” - 解决方法:把其中一端改成
weak_ptr,访问前用lock()检查是否还活着 - 注意:
weak_ptr不增加引用计数,但不能直接解引用,必须转成shared_ptr才能用
shared_ptr 构造时避免隐式转换和临时对象陷阱
直接用裸指针构造 shared_ptr 很危险,容易在构造完成前就发生异常,导致裸指针丢失、无智能指针接管。
- 错误写法:
func(shared_ptr<t>(new T), other_arg());</t>→ 若other_arg()抛异常,new T就泄漏了 - 正确写法:用
make_shared,它原子性地分配控制块和对象,且不会出现中间态泄漏 - 例外:需要自定义删除器或分配器时,
make_shared不支持,只能用shared_ptr构造函数,但务必确保裸指针只出现在单独一行、不参与其他表达式
跨 DLL/so 边界传递 shared_ptr 的风险
不同模块可能用不同 STL 实现或不同编译选项(如 _HAS_ITERATOR_DEBUGGING),导致 shared_ptr 控制块布局不一致,析构时崩溃或跳过析构函数。
立即学习“C++免费学习笔记(深入)”;
- 现象:程序在卸载 DLL 后 crash,或对象析构函数完全没被调用
- 根本原因:控制块里的虚表、引用计数字段偏移不一致,
shared_ptr误读计数,提前释放或永不释放 - 建议:跨模块只传裸指针 + 明确所有权协议,或统一使用 COM 风格接口(AddRef/Release)
- 若必须传
shared_ptr,确保所有模块用同一套编译器、标准库、ABI 设置(例如全用 MSVC + /MDd)
shared_ptr 不是银弹,它的“自动”依赖于你始终清楚谁在持有哪些引用、控制块在哪分配、析构逻辑是否跨边界生效。很多泄漏不是忘了用智能指针,而是用了却没看清引用关系或生命周期边界。










