shared_ptr初始化必须用make_shared,因其一次性分配控制块和对象内存,更高效且避免异常导致的内存泄漏;仅在需自定义删除器或兼容裸指针时才用new,但须确保无异常风险。

shared_ptr 初始化时为什么不能直接用 new
因为 shared_ptr 的构造函数不接受裸指针的隐式转换,直接写 shared_ptr<int> p = new int(42);</int> 会编译失败。它要求显式构造或使用 make_shared —— 后者更安全、更高效。
常见错误现象:error: no viable conversion from 'int *' to 'shared_ptr<int>'</int>
- 正确做法:用
std::make_shared<int>(42)</int>(推荐) - 或显式构造:
shared_ptr<int> p(new int(42))</int>(不推荐,异常安全风险高) -
make_shared一次性分配对象和控制块内存,减少一次堆分配;而裸指针构造方式需两次分配 - 如果
new成功但控制块构造失败(如内存不足),裸指针会泄漏
shared_ptr 赋值和拷贝后引用计数怎么变
每次拷贝或赋值都会使内部引用计数 +1,析构或重置时 -1;计数归零才真正 delete 对象。这不是“共享所有权”的比喻,是精确可测的行为。
使用场景:多个模块/线程需要共同持有同一资源,且无明确主控方
- 拷贝构造:
auto p2 = p1;→ 计数 +1 - 赋值:
p2 = p1;→ 原p2计数 -1,p1计数 +1 - 用
p.reset()或离开作用域 → 计数 -1 - 注意:
shared_ptr拷贝是浅拷贝,但语义上是“共享所有权”,不是“共享地址”
循环引用导致内存泄漏怎么破
shared_ptr 自身无法打破循环引用,必须手动介入 —— 最常用的是把其中一端换成 weak_ptr。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
典型错误模式:两个类互相用 shared_ptr 持有对方,析构时谁都等不到对方先释放
- 示例:A 里存
shared_ptr<b></b>,B 里存shared_ptr<a></a>→ 引用计数永远 ≥1 - 修复:B 中改用
weak_ptr<a></a>,访问前调用lock()转成临时shared_ptr -
weak_ptr不增加引用计数,也不阻止对象销毁;lock()返回空shared_ptr表示原对象已释放 - 别试图用
reset()手动打断——时机难控,且多线程下易竞态
自定义删除器为什么必须匹配类型
传给 shared_ptr 的删除器(deleter)类型是模板参数的一部分,一旦指定,就绑定到该实例的整个生命周期;类型不匹配会导致编译失败或未定义行为。
使用场景:管理非 new 分配的资源,如 C 风格句柄、mmap 内存、SDL_Texture 等
- 正确写法:
shared_ptr<int> p(ptr, [](int* p) { delete[] p; });</int>(对应new[]) - 错误写法:
shared_ptr<int> p(new int[10], [](int* p) { delete p; });</int>→ 未定义行为 - 删除器类型影响
shared_ptr对象大小:函数对象若捕获变量,可能增大体积;无状态 lambda 通常零开销 - 避免用
std::function做删除器——它引入虚调用和额外堆分配,违背智能指针轻量初衷
引用计数本身是原子操作,但 shared_ptr 对象的读写仍需外部同步;很多人以为“用了 shared_ptr 就线程安全”,其实只保证控制块安全,指向的对象内容完全不管。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










