必须用 std::unique_ptr 而不是裸指针的情况是:需要自动释放堆内存且明确禁止多所有者共享资源时,因其独占所有权、仅支持移动、编译期阻止拷贝,可杜绝手动 delete 遗漏、异常泄漏及双重释放。
std::unique_ptr 而不是裸指针当你需要自动释放堆内存、且明确不允许多个所有者共享同一块资源时,std::unique_ptr 是唯一合理选择。它不是“更安全的替代品”,而是语义约束工具:所有权不可复制,只能移动。
常见误用场景包括:new 后手动 delete 忘记、异常路径漏释放、函数返回裸指针导致调用方责任模糊。这些都会直接导致内存泄漏或双重释放。
std::unique_ptr p(new int(42)); (不推荐,应优先用 make_unique)auto p = std::make_unique(42);
if (!p) { /* p 为空 */ } 或 if (p == nullptr)
std::unique_ptr 的移动语义和禁止拷贝规则std::unique_ptr 显式删除了拷贝构造函数和拷贝赋值运算符,任何试图复制它的操作都会在编译期报错,错误信息类似:use of deleted function ‘std::unique_ptr<_tp _dp>::unique_ptr(const std::unique_ptr<_tp _dp>&)’。
移动是唯一合法的所有权转移方式:
立即学习“C++免费学习笔记(深入)”;
std::unique_ptra = std::make_unique (100); std::unique_ptr b = std::move(a); // a 现在为空,b 持有原资源 // std::unique_ptr c = a; / / 编译失败
std::unique_ptr&& 接收移动,或直接按值传(隐式移动)std::unique_ptr,调用方自动获得所有权std::vector<:unique_ptr>> vec; 合法;但不能用 std::shared_ptr 或裸指针混用逻辑默认情况下 std::unique_ptr 用 delete 释放内存,但很多 C 风格 API 返回的资源需要特定清理函数,比如 fopen/fclose、malloc/free、Windows CreateFile/CloseHandle。
这时必须提供自定义 deleter,否则资源不会被正确释放:
auto file_deleter = [](FILE* f) { if (f) fclose(f); };
std::unique_ptr fp(fopen("test.txt", "r"), file_deleter); std::unique_ptr
[&x]{...}),无法作为模板参数推导,需改用函数对象或 std::function(但会增加开销)std::unique_ptr,否则 delete 被用于 new[] 内存,UBstd::shared_ptr 混用时的典型崩溃点绝对不能把同一个裸指针分别交给 std::unique_ptr 和 std::shared_ptr 管理,哪怕只创建一次。两者各自维护独立的控制块,最终都会尝试释放同一块内存,造成双重释放。
例如以下代码是危险的:
int* raw = new int(42); std::unique_ptru(raw); std::shared_ptr s(raw); // 错!s 和 u 各自 delete raw
make_unique / make_shared,要么确保裸指针只被一个智能指针接管std::shared_ptr 构造函数接收 std::unique_ptr(会移动并接管):std::shared_ptr s = std::move(u);
std::unique_ptr 时,注意分配器/删除器是否匹配(尤其 Windows 上 CRT 多版本问题)实际项目里最常出问题的不是语法写错,而是所有权边界没想清楚——比如该由谁释放、哪一层该持有、是否可能被意外移动走。写完记得问自己一句:这个指针的生命周期,是否真的只属于当前作用域或对象?