std::unique_ptr 禁止拷贝,只支持移动,强制明确内存管理责任;传参用引用(只读)或按值(接管),移动后原指针失效;与裸指针或 shared_ptr 混用易导致 double free 或悬空。

std::unique_ptr 的所有权不能复制,只能移动
独占语义的核心就一句话:std::unique_ptr 禁止拷贝构造和拷贝赋值,只允许移动。这不是设计缺陷,而是刻意为之——它用编译器强制你面对“谁负责释放内存”这个问题。
常见错误现象:error: use of deleted function 'std::unique_ptr,通常出现在试图把 std::unique_ptr 当普通参数传给函数、或放进 std::vector 时直接 push_back 拷贝。
- 想传入函数处理?用
std::unique_ptr(引用)或& const std::unique_ptr(只读访问)& - 想把所有权交出去?必须显式调用
std::move(ptr),且之后原变量进入有效但未定义状态(不能再解引用) - 想返回新所有权?函数返回类型写
std::unique_ptr,return 时也得用std::move或直接构造(如return std::make_unique)()
std::move 不是“移动”,只是类型转换
std::move 本身不搬数据、不调析构、不改内存,它只是把左值强制转成右值引用,好让编译器选中移动构造/移动赋值重载。很多人以为写了 std::move 就安全了,其实不是。
使用场景:只有在你明确要放弃当前变量的所有权时才用。比如函数返回一个局部 std::unique_ptr,或者把某个指针交给另一个作用域管理。
立即学习“C++免费学习笔记(深入)”;
- 错误用法:
std::unique_ptr——p = std::make_unique (42); auto q = std::move(p); *p = 100; p已失效,解引用是未定义行为 - 正确习惯:移动后立即置空(
p.reset())或不再使用,尤其在条件分支里容易漏掉 - 性能影响:移动
std::unique_ptr是 O(1),比深拷贝快得多,但别为了“看起来高效”滥用std::move
函数参数怎么写,取决于你想要什么语义
传 std::unique_ptr 进函数,三种写法对应三种意图,不能混用:
- 只读访问:用
const std::unique_ptr—— 不影响所有权,函数内不能转移走& - 接管所有权:用
std::unique_ptr(按值)—— 调用方必须std::move,函数获得唯一控制权 - 可能修改内部对象但不接管:用
T*或T&—— 最轻量,不涉及智能指针生命周期,适合纯业务逻辑
容易踩的坑:把按值接收的函数误当成“可拷贝”,结果在调用处忘了 std::move;或者把 std::unique_ptr 当成能转移的入口,实际函数体里没调 std::move,导致所有权滞留在调用方。
和 raw pointer / shared_ptr 混用要格外小心
std::unique_ptr 和裸指针之间可以双向转换(.get() 取地址,std::unique_ptr 接管),但一旦交出去,你就得确保没人再用那个裸指针——否则 double free 或悬空指针立刻出现。
和 std::shared_ptr 互转更危险:std::shared_ptr 构造时会接管 std::unique_ptr 的原始指针,但此时 std::unique_ptr 已被 move 空,而 std::shared_ptr 的引用计数机制和 std::unique_ptr 的独占假设完全冲突。
- 禁止:用同一个裸指针同时初始化
std::unique_ptr和std::shared_ptr - 禁止:从
std::unique_ptr.get()得到的指针,再拿去 new 一个std::shared_ptr - 建议:需要共享语义?一开始就用
std::shared_ptr;需要独占?全程别暴露裸指针
真正难的不是语法,是每次拿到一个 std::unique_ptr 时,都得问一句:这个指针现在归谁管?我动它,会不会让别人崩溃?










