unique_ptr 不能拷贝只能移动,核心语义是独占所有权;正确转移需用 std::move;传参须用值类型或右值引用;返回时自动移动;推荐 make_unique 构造,避免 new 导致异常泄漏;支持自定义删除器但类型不兼容;裸指针仅限临时观察,不可长期持有或 delete。

unique_ptr 不能拷贝,只能移动
你写 std::unique_ptr<int> p1 = std::make_unique<int>(42); auto p2 = p1;</int></int>,编译器会直接报错:use of deleted function 'std::unique_ptr<_tp _dp>::unique_ptr(const std::unique_ptr<_tp _dp>&)'</_tp></_tp>。这是设计使然——unique_ptr 的核心语义就是“独占所有权”,不允许多个指针同时指向同一块内存。
正确做法是显式转移控制权:
- 用
std::move(p1)赋值给另一个unique_ptr,此时p1变成空(p1 == nullptr) - 函数传参时,如果想把所有权交给函数,参数类型必须是
std::unique_ptr<t></t>或std::unique_ptr<t>&&</t>,不能是const std::unique_ptr<t>&</t>(它阻止移动) - 返回
unique_ptr没问题,现代 C++ 会自动触发移动,不用写std::move
make_unique 是唯一推荐的构造方式
别手写 new 配合 unique_ptr 构造,比如 std::unique_ptr<int>(new int(42))</int> —— 它在异常场景下有内存泄漏风险:如果后续对象构造抛异常,new 出来的内存没人接管。
std::make_unique 是原子操作,内部保证了“分配 + 构造”要么全成功,要么全失败:
立即学习“C++免费学习笔记(深入)”;
- 数组支持:用
std::make_unique<int>(100)</int>,不是std::make_unique<int></int> - 自定义删除器不能用
make_unique,必须手写构造,例如带fclose的FILE*管理 - 它不支持初始化列表(如
{1,2,3}),要初始化容器得换std::vector等
释放时机确定,但析构行为可定制
unique_ptr 在离开作用域、被赋新值或显式调用 reset() 时,自动调用其关联的删除器(deleter)。默认是 delete 或 delete[],但你可以换:
- 对 C 风格资源,比如
FILE*,用std::unique_ptr<file decltype></file>配合std::make_unique不可用,得写std::unique_ptr<file void>(fopen(...), &fclose)</file> - 删除器类型是模板参数的一部分,不同删除器的
unique_ptr类型不兼容,不能直接赋值 - 空
unique_ptr(比如刚构造未赋值)调用reset()或离开作用域,不会触发删除器
和 raw pointer 混用时最容易出错
常见错误是把 unique_ptr.get() 返回的裸指针存太久,或者用它去 delete —— get() 只是临时借阅,不移交所有权,原 unique_ptr 仍会在析构时 delete 它。
- 裸指针仅限只读观察、传给 C API、或短期传入不存储的函数;绝不能保存为成员变量或长期持有
-
release()会交出所有权并置空自身,返回裸指针——之后必须手动管理,否则泄漏 - 从函数返回裸指针再包进另一个
unique_ptr?危险!除非你 100% 确认原所有者已放弃管理,否则 double-delete
真正难的不是语法,而是判断“谁该拥有这块内存”。一旦跨线程、进容器、或和 C 接口打交道,所有权边界就容易模糊。这时候多看一眼 get() 和 release() 的调用点,比背规则管用。









