unique_ptr 不能复制只能移动,出生即绑定资源、析构自动释放;最安全创建方式是 std::make_unique,支持数组和自定义删除器,访问前需判空,release/reset 控制释放,误用易致未定义行为。

unique_ptr 不能复制,只能移动;它一出生就绑定资源,析构时自动释放——这是它实现独占式资源管理的核心机制。
怎么创建和初始化 unique_ptr
最安全的方式是用 std::make_unique,它避免裸 new 可能引发的异常安全问题(比如构造参数中抛异常导致内存泄漏)。
- 正确:
auto ptr = std::make_unique
(42); - 不推荐:
std::unique_ptr
(裸 new 容易出错,且无法传递数组长度)ptr(new int(42)); - 数组支持:
auto arr = std::make_unique
,此时调用的是(10); // 注意 [] 语法 delete[] - 自定义删除器必须在构造时指定,不能后期修改:
std::unique_ptr
ptr(new int(42), [](int* p) { delete p; });
为什么不能拷贝,只能移动
拷贝语义会破坏“独占”前提:两个指针同时指向同一块内存,谁析构谁负责?unique_ptr 的拷贝构造函数和 operator= 都被显式 delete 了。
- 错误写法:
auto p1 = std::make_unique
(1); auto p2 = p1; // 编译失败:use of deleted function - 正确转移所有权:
auto p2 = std::move(p1); // p1 变成 nullptr,p2 持有资源
- 函数传参/返回也必须用移动:
void take(std::unique_ptr
p) { /* p 接收所有权 */ } auto p = std::make_unique (1); take(std::move(p)); // p 此后为空
如何安全访问和释放资源
直接解引用前务必检查是否为空,否则触发未定义行为;显式释放用 release(),但要自己承担后续释放责任。
立即学习“C++免费学习笔记(深入)”;
- 访问:
ptr.get()返回原始指针(只读),*ptr或ptr->member解引用(需确保非空) - 判空:
if (ptr)或if (ptr != nullptr),别用if (ptr.get())多此一举 - 手动交出控制权:
int* raw = ptr.release(); // ptr 变成 nullptr,raw 必须手动 delete
- 重置资源:
ptr.reset(new int(99))会先释放旧资源再接管新资源;ptr.reset()等价于ptr = nullptr
常见误用和陷阱
最容易被忽略的是数组类型和自定义删除器的匹配问题——类型系统不会帮你校验删除器逻辑是否正确。
- 用
make_unique创建数组,却用普通unique_ptr接收 → 编译报错(类型不匹配) - 手动 new 数组,却用默认删除器的
unique_ptr管理 →delete而非delete[],UB - 把
unique_ptr存入容器(如std::vector<:unique_ptr>>)没问题,但存进std::set或作为std::mapkey 就不行——因为不可比较、不可拷贝 - 跨 DLL 边界传递
unique_ptr(尤其带自定义删除器)可能因 ABI 不一致崩溃,优先用裸指针 + 明确约定生命周期
真正难的不是语法,而是判断“该不该用 unique_ptr”:如果资源需要共享或延迟释放,它就不是解;如果对象生命周期本就由栈管理,加一层 unique_ptr 反而增加间接性。它的价值只在“我确定只有我管这块内存,且我走的时候必须清掉”。










