
std::unique_ptr 为什么不能拷贝?
因为 std::unique_ptr 的设计目标就是「独占所有权」——同一块内存只能被一个 std::unique_ptr 持有。一旦允许拷贝,就会出现两个对象同时认为自己负责释放同一块内存,导致重复 delete、未定义行为或崩溃。
编译器直接禁用了拷贝构造函数和拷贝赋值运算符,所以像 auto p2 = p1; 或 p2 = p1; 这种写法会报错:use of deleted function。
- 想转移所有权?必须用
std::move(p1)显式声明“我放弃控制权” - 误写成
p2 = p1;是新手最常踩的坑,错误信息里带deleted就该立刻想到是不是忘了std::move - 移动后
p1.get() == nullptr,别再对它解引用,否则段错误
如何正确初始化 unique_ptr(尤其是带自定义删除器)
裸指针转 std::unique_ptr 必须用 new 配合构造函数,不能用 = new T 赋值(语法不支持),也不能用 reset() 替代初始化(容易漏掉异常安全场景)。
自定义删除器不是可选优化项——比如用 malloc 分配的内存,就必须传 free;打开的文件描述符得用 close;否则资源根本不会被清理。
立即学习“C++免费学习笔记(深入)”;
- 推荐写法:
auto ptr = std::unique_ptr<int>(new int(42));</int>或更安全的std::make_unique<int>(42)</int> - 带删除器示例:
std::unique_ptr<int void> ptr(new int(42), [](int* p) { free(p); });</int>(注意类型必须匹配) - 用
std::make_unique无法指定自定义删除器,此时只能手写构造 - 删除器类型是
unique_ptr模板参数的一部分,std::unique_ptr<int></int>和std::unique_ptr<int decltype></int>是完全不同的类型
unique_ptr 作函数参数时,传值 vs 传引用的区别
传值意味着所有权移交,调用方失去访问权;传引用(const std::unique_ptr<t>&</t> 或 std::unique_ptr<t>&</t>)只是临时观察或修改内部指针,不改变所有权。
常见错误是函数声明想“只读访问”,却写了 std::unique_ptr<t></t> 参数,结果调用方莫名其妙丢失资源。
- 需要接管资源?函数参数写
std::unique_ptr<t></t>,调用时用std::move(ptr) - 只读访问?用
const std::unique_ptr<t>&</t>,但注意:这并不能防止底层对象被修改(*ptr = 123仍合法) - 想修改所指对象内容,又不想交出所有权?还是用
std::unique_ptr<t>&</t>,但要确保调用方明确知道你在改它的数据 - 更轻量、更通用的做法是传
T*或T&,除非函数语义上确实需要“接收并管理这块内存”
和 raw pointer 混用时最容易忽略的陷阱
std::unique_ptr 不是万能胶布,它只管自己那一份所有权。一旦你从它那里拿到裸指针(ptr.get()),就脱离了 RAII 管理——后续任何异常、提前 return、或者忘记重置,都会导致悬空指针或泄漏。
尤其危险的是把 get() 结果存进容器、传给 C 接口、或长期缓存,而没同步维护生命周期逻辑。
-
ptr.get()返回的指针仅在ptr有效期间有效,绝不能保存下来等它析构后再用 - 向 C 函数传参常用
ptr.get(),但必须确保 C 函数不会保存该指针用于后续异步回调 - 不要用
ptr.release()除非你真打算手动管理——它把控制权彻底交还给你,unique_ptr再不管了 - 调试时发现
ptr.get()返回nullptr?先检查是否已被move、reset或已析构
所有权边界越清晰,bug 越少。但「唯一所有权」本身就意味着不能绕过规则去共享——真需要共享,请换 std::shared_ptr,别硬用 unique_ptr 加裸指针模拟。










