信息发布→ 登录 注册 退出

c++ unique_ptr用法_c++独占智能指针教程

发布时间:2026-01-05

点击量:
必须用 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_ptr a = 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 或裸指针混用逻辑

自定义删除器(deleter)的实际用途和陷阱

默认情况下 std::unique_ptrdelete 释放内存,但很多 C 风格 API 返回的资源需要特定清理函数,比如 fopen/fclosemalloc/free、Windows CreateFile/CloseHandle

这时必须提供自定义 deleter,否则资源不会被正确释放:

auto file_deleter = [](FILE* f) { if (f) fclose(f); };
std::unique_ptr fp(fopen("test.txt", "r"), file_deleter);
  • deleter 类型必须作为模板参数显式写出,否则编译失败:std::unique_ptr
  • lambda 表达式若含捕获([&x]{...}),无法作为模板参数推导,需改用函数对象或 std::function(但会增加开销)
  • 数组版本必须用 std::unique_ptr,否则 delete 被用于 new[] 内存,UB

std::shared_ptr 混用时的典型崩溃点

绝对不能把同一个裸指针分别交给 std::unique_ptrstd::shared_ptr 管理,哪怕只创建一次。两者各自维护独立的控制块,最终都会尝试释放同一块内存,造成双重释放。

例如以下代码是危险的:

int* raw = new int(42);
std::unique_ptr u(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);
  • 跨 DLL 边界传递 std::unique_ptr 时,注意分配器/删除器是否匹配(尤其 Windows 上 CRT 多版本问题)

实际项目里最常出问题的不是语法写错,而是所有权边界没想清楚——比如该由谁释放、哪一层该持有、是否可能被意外移动走。写完记得问自己一句:这个指针的生命周期,是否真的只属于当前作用域或对象?

标签:# 指针  # 能把  # 绝对不  # 是唯一  # 当你  # 什么时候  # 多个  # 一句  # 而不是  # 为空  # 自定义  # 对象  # function  # delete  # 空指针  #   # windows  # int  # auto  # const  # fclose  # fopen  # 构造函数  # if  # 赋值运算符  # 运算符  # red  # 作用域  # win  # c++  # 工具  
在线客服
服务热线

服务热线

4008888355

微信咨询
二维码
返回顶部
×二维码

截屏,微信识别二维码

打开微信

微信号已复制,请打开微信添加咨询详情!