unique_ptr 禁止拷贝,只支持 move 转移所有权;必须用 std::move 显式转移,转移后原指针为空;推荐 std::make_unique 创建,函数参数宜用 && 接收,可单向转 shared_ptr。

unique_ptr 不能拷贝,只能 move 转移所有权
这是 unique_ptr 的核心约束:它禁止拷贝构造和拷贝赋值,只允许移动(std::move)。一旦你尝试写 auto p2 = p1; 或 auto p2(p1);,编译器会直接报错——典型错误信息是 use of deleted function。
原因很简单:unique_ptr 的设计目标就是「独占资源」,不允许两个指针同时指向同一块堆内存。转移所有权必须显式、无歧义。
- 正确做法永远是
auto p2 = std::move(p1);,转移后p1变成空(p1 == nullptr) - 函数传参/返回时也必须用
std::move(如果原变量是左值)或直接返回临时对象(右值自动触发移动) - 不要对已 move 过的
unique_ptr再解引用或调用get(),否则行为未定义
创建 unique_ptr 的常见方式和陷阱
最安全的是用 std::make_unique(C++14 起),它避免裸 new 和异常安全问题;C++11 中需手动配对 new + unique_ptr 构造。
-
auto p = std::make_unique—— 推荐,简洁且异常安全(42); -
auto p = std::unique_ptr—— C++11 兼容,但若(new int(42)); new后构造失败(比如自定义类型抛异常),可能泄漏 -
std::unique_ptr—— 数组特化版本,析构时自动调用arr(new int[10]); delete[],不能用make_unique创建数组(C++14 才支持make_unique)
unique_ptr 作为函数参数和返回值怎么写
函数接口设计直接影响所有权流向,必须和调用方达成明确契约:
立即学习“C++免费学习笔记(深入)”;
- 接收
std::unique_ptr:函数要接管所有权,调用方必须用&& std::move传入 - 接收
const std::unique_ptr:仅读取,不改变所有权(但很少见,通常直接传原始指针& T*更清晰) - 返回
std::unique_ptr:函数移交所有权,返回值是右值,调用方可直接赋给另一个unique_ptr(自动 move) - 错误示范:
void f(std::unique_ptr看似“传值”,实则每次调用都强制 move,容易让调用方误以为可复用原变量p)
示例:
std::unique_ptrcreate_int() { return std::make_unique (100); // OK,返回右值,自动 move } auto p = create_int(); // p 拿到所有权,create_int 内部资源被移交
和 shared_ptr 混用或转换时的注意事项
unique_ptr 可以**单向转**为 shared_ptr(通过构造函数),但反过来不行——因为共享所有权无法降级为独占。
-
std::shared_ptr—— 合法,sp(std::move(up)); up变为空,sp接管并开始计数 -
std::unique_ptr—— 编译失败,没有对应构造函数up(sp); - 不要用
up.release()后手动交给shared_ptr,这绕过 RAII,极易出错;应始终优先用 move 构造 - 多线程中,
unique_ptr本身不是线程安全的;若需在线程间传递所有权,move 是唯一安全方式,但 move 操作本身需确保不与其他访问冲突
真正容易被忽略的是:move 后的 unique_ptr 并非“无效”,而是处于合法的空状态(!p 为 true),仍可再次赋值或 reset,但绝不该再用 *p 或 p->foo()。










