shared_ptr应优先用make_shared初始化以避免额外内存分配和异常安全问题;unique_ptr不可拷贝只能移动,表示独占所有权;二者混用需谨慎,转换后原unique_ptr为空。

shared_ptr 初始化必须用 make_shared
直接 new 配合 shared_ptr 构造函数看似可行,但会多一次内存分配,还可能引发异常安全问题。make_shared 把控制块和对象内存一次性分配,更高效也更安全。
常见错误现象:shared_ptr<int>(new int(42))</int> 编译通过,但性能差、异常时可能泄漏;make_shared<int>(42)</int> 才是推荐写法。
- 不要对裸指针调用
shared_ptr::reset(),容易重复释放 - 避免循环引用:两个
shared_ptr互相持有对方,引用计数永远不为 0,得用weak_ptr打断 -
make_shared不支持自定义删除器,需要时才退回到构造函数形式
unique_ptr 不能拷贝,只能移动
这是它和 shared_ptr 最根本的区别——unique_ptr 表示独占所有权,拷贝操作被显式删除。所有传递、返回、赋值都必须用 std::move。
使用场景:函数返回动态对象、容器里存堆对象、RAII 资源封装(比如文件句柄、socket)。
立即学习“C++免费学习笔记(深入)”;
- 传参时用
unique_ptr<t>&&</t>或直接按值接收(触发移动) - 往
vector里 push,必须写v.push_back(std::move(p)),否则编译失败 - 初始化可用
make_unique(C++14 起),比new更安全,支持参数转发
shared_ptr 和 unique_ptr 混用要小心类型擦除
把 unique_ptr 转成 shared_ptr 是合法的(通过移动),但反过来不行。一旦转成 shared_ptr,就失去独占语义,后续谁都可能复制它。
典型误用:shared_ptr<t> sp = std::move(up);</t> 后继续用 up —— 此时 up 已为空,解引用必崩。
- 转换只应在明确放弃独占权、交由共享管理时发生
- 不要在函数参数里写
shared_ptr<t>(std::move(unique_ptr<t>))</t></t>,可读性差且易出错 - 注意
shared_ptr的控制块开销:每个实例额外占用约 16 字节(含引用计数、弱引用计数、删除器等)
自定义删除器写法差异很大
unique_ptr 的删除器是模板参数,影响类型;shared_ptr 的删除器是运行时对象,类型擦除后不参与模板实例化。
这意味着:带不同删除器的两个 unique_ptr 是不同类型,不能赋值;而 shared_ptr 只要指向同类型对象,就能互相赋值,不管删除器是否相同。
-
unique_ptr<FILE, decltype(&fclose)> fp(fopen("x", "r"), &fclose);删除器类型必须精确匹配 -
shared_ptr<FILE> sp(fopen("x", "r"), [](FILE* f) { if (f) fclose(f); });删除器是值语义,可捕获、可 lambda - 自定义删除器若抛异常,
unique_ptr析构时直接 terminate,shared_ptr则不会(但资源可能泄漏)
事情说清了就结束











