shared_ptr初始化必须用make_shared或new,禁用栈变量地址;禁止用get()构造新shared_ptr;循环引用需weak_ptr打破;自定义删除器须类型稳定且不抛异常。

shared_ptr 初始化必须用 new 或 make_shared
直接把栈变量地址传给 shared_ptr 是危险操作,编译器不会报错,但运行时大概率崩溃。因为 shared_ptr 默认会调用 delete 释放资源,而栈变量不能 delete。
- ✅ 正确:用
std::make_shared<int>(42)</int>—— 推荐,一次分配对象+控制块,性能更好 - ✅ 正确:用
std::shared_ptr<int>(new int(42))</int>—— 可行但不推荐,两次内存分配 - ❌ 错误:
int x = 42; std::shared_ptr<int> p(&x);</int>—— 程序退出时会尝试delete &x,UB(未定义行为)
别用 get() 返回的裸指针去构造另一个 shared_ptr
get() 只是临时取地址,不代表所有权移交。拿它再建一个 shared_ptr,会导致两个智能指针各自管理同一块内存,析构时 double-delete。
- 常见错误现象:
double free or corruption、段错误、随机崩溃 - 错误写法:
auto p1 = std::make_shared<int>(100); auto p2 = std::shared_ptr<int>(p1.get());</int></int> - 正确做法:需要共享所有权就直接赋值或拷贝:
auto p2 = p1;,引用计数自动 +1 - 如果真要裸指针(比如传给 C API),确保不拿它再造智能指针
循环引用时得用 weak_ptr 打断
shared_ptr 的引用计数只在最后一个实例析构时才真正释放资源。父子互相持有时,引用计数永远不为 0,导致内存泄漏。
- 典型场景:树节点、观察者模式、双向链表节点
- 解决方式:一方用
std::weak_ptr持有另一方,访问前用lock()转成临时shared_ptr - 示例:
struct Node { std::shared_ptr<node> parent; std::weak_ptr<node> child; };</node></node> - 注意:
weak_ptr::lock()返回空shared_ptr表示原对象已销毁,必须检查
自定义删除器要注意类型匹配和生命周期
给 shared_ptr 配自定义删除器(比如关文件、释放 C 资源)时,删除器类型会参与模板推导,影响对象布局和兼容性。
立即学习“C++免费学习笔记(深入)”;
- 常见坑:用 lambda 当删除器时,每个 lambda 类型都不同,导致无法赋值给同一类型
shared_ptr - 解决办法:显式指定删除器类型,或用
std::function<void></void>包一层(但有轻微开销) - 更稳妥:用函数指针或仿函数类,类型稳定,例如
struct FileDeleter { void operator()(FILE* f) { fclose(f); } }; - 删除器本身不能抛异常,否则
shared_ptr析构可能中止程序
事情说清了就结束。最常出问题的地方不在语法,而在所有权边界没想清楚——尤其是跨模块传递、混用裸指针、以及忘了 weak_ptr 的存在。










