惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

N
Netflix TechBlog - Medium
V
Vulnerabilities – Threatpost
Google Online Security Blog
Google Online Security Blog
Hugging Face - Blog
Hugging Face - Blog
L
LINUX DO - 热门话题
云风的 BLOG
云风的 BLOG
P
Proofpoint News Feed
D
Docker
C
Cyber Attacks, Cyber Crime and Cyber Security
MyScale Blog
MyScale Blog
P
Palo Alto Networks Blog
T
Tenable Blog
P
Privacy International News Feed
Google DeepMind News
Google DeepMind News
小众软件
小众软件
Cisco Talos Blog
Cisco Talos Blog
aimingoo的专栏
aimingoo的专栏
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
A
Arctic Wolf
C
Cybersecurity and Infrastructure Security Agency CISA
C
Cisco Blogs
T
Threat Research - Cisco Blogs
NISL@THU
NISL@THU
The Hacker News
The Hacker News
Project Zero
Project Zero
AWS News Blog
AWS News Blog
Simon Willison's Weblog
Simon Willison's Weblog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
T
Threatpost
V
Visual Studio Blog
The GitHub Blog
The GitHub Blog
The Cloudflare Blog
Last Week in AI
Last Week in AI
Jina AI
Jina AI
Cyberwarzone
Cyberwarzone
The Register - Security
The Register - Security
C
CXSECURITY Database RSS Feed - CXSecurity.com
Vercel News
Vercel News
D
Darknet – Hacking Tools, Hacker News & Cyber Security
MongoDB | Blog
MongoDB | Blog
U
Unit 42
Scott Helme
Scott Helme
A
About on SuperTechFans
WordPress大学
WordPress大学
F
Fortinet All Blogs
大猫的无限游戏
大猫的无限游戏
G
GRAHAM CLULEY
Latest news
Latest news
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
S
Schneier on Security

博客园 - double64

C++ 安全的拷贝赋值(Copy-and-Swap 惯用法) C++ 基类派生类的 static_cast 和 dynamic_cast 转换的简单测试 visual studio 的 snippet 代码片段模板样式 Windows 右键管理官方小程序Autoruns C++ 结合 enum 按位与或组合检测枚举项 std::unique_ptr 当删除器类型为 无状态的时构造可以不用传删除器示例 两个用来写 CLI - Command-Line Interface 的命令解析库 enum class 类型转换 int 微软输入法中如何输出当前时间 音程知识 C++ 模板引用参数的各种情况 英语 12 种时态 Qt 手动添加 Q_OBJECT 需要添加的地方 C# WPF 绑定 ObservableObject 实现 INotifyPropertyChanged 接口 C++ 标准库 copy_if C++ lambda 和 bind 何时优先使用 Windows 下的 Qt 中 min max 函数冲突 C++ RVO 或 NRVO 可能触发的条件 C++ 智能指针和动态数组 std::vector 插入另一个 vector 的范围元素 Qt tableWidget QTableWidget 常用一些属性设置 C++ 内部类(嵌套类)是可以访问外部类的私有保护成员的 C++ 宏展开顺序 C++ std::round() 四舍五入 cv::Mat 和 HalconCpp::HImage 生成和保存图像简单测试 简单易用的图像库:stb_image Halcon HImage 与 Qt QImage 的相互转换
C++ std::unique_ptr 和 std::shared_ptr 都支持自定义删除器(deleter)
double64 · 2025-05-23 · via 博客园 - double64

在 C++ 中,std::unique_ptrstd::shared_ptr 都支持自定义删除器(deleter),但它们在实现和使用上有一些关键区别。以下是它们的异同点:


相同点

  1. 支持自定义删除器
    两者都允许通过模板参数或构造函数参数指定删除器,用于管理资源释放(如文件句柄、内存、网络连接等)。

  2. 默认删除器行为相同
    如果不指定删除器,两者默认使用 deletedelete[](针对数组版本)释放资源。


不同点

1. 删除器的存储方式

  • std::unique_ptr

    • 删除器是类型的一部分(通过模板参数指定),存储在智能指针对象内部。
    • 如果未指定删除器,默认使用 std::default_delete<T>
    • 由于删除器是类型的一部分,不同删除器的 unique_ptr 是不同类型,不能直接互相赋值或传递。
    • 示例:
      std::unique_ptr<FILE, decltype(&fclose)> file(fopen("test.txt", "r"), &fclose);
      
  • std::shared_ptr

    • 删除器不是类型的一部分,而是通过构造函数参数动态绑定,存储在控制块中。
    • 无论删除器如何,shared_ptr 的类型始终是 std::shared_ptr<T>,因此不同删除器的 shared_ptr 可以互相赋值或传递。
    • 示例:
      std::shared_ptr<FILE> file(fopen("test.txt", "r"), &fclose);
      

2. 性能影响

  • std::unique_ptr

    • 删除器是编译期确定的,无运行时开销(可能被内联优化)。
    • 对象大小可能因删除器类型而变化(例如函数指针会增加指针大小)。
  • std::shared_ptr

    • 删除器存储在动态分配的控制块中,可能带来轻微运行时开销。
    • 对象大小固定(通常为两个指针,指向对象和控制块)。

3. 灵活性与类型擦除

  • std::unique_ptr

    • 删除器是类型的一部分,灵活性较低(需要显式指定模板参数)。
    • 适合简单场景或需要极致性能的情况。
  • std::shared_ptr

    • 删除器通过类型擦除(type erasure)实现,灵活性更高。
    • 可以捕获任意可调用对象(如函数、lambda、仿函数),无需在类型中显式声明。
    • 示例:
      auto deleter = [](FILE* f) { fclose(f); };
      std::shared_ptr<FILE> file(fopen("test.txt", "r"), deleter);
      

4. 数组支持

  • std::unique_ptr

    • 显式支持数组形式(std::unique_ptr<T[]>),默认调用 delete[]
    • 示例:
      std::unique_ptr<int[]> arr(new int[10]);
      
  • std::shared_ptr

    • 不直接支持数组形式(C++17 前需手动指定删除器 delete[])。
    • C++17 起可用 std::default_delete<T[]>std::make_shared 的扩展。
    • 示例:
      std::shared_ptr<int> arr(new int[10], std::default_delete<int[]>());
      

总结表格

特性 std::unique_ptr std::shared_ptr
删除器存储位置 编译期确定(类型的一部分) 运行时动态存储(控制块中)
类型影响 删除器不同则类型不同 删除器不影响类型
性能 无额外开销 轻微运行时开销
灵活性 需显式指定模板参数 支持任意可调用对象
数组支持 直接支持(unique_ptr<T[]> 需手动指定删除器(如 default_delete<T[]>

使用建议

  • 优先用 std::unique_ptr,除非需要共享所有权。
  • 需要灵活删除器时(如捕获状态的 lambda),选择 std::shared_ptr
  • 数组资源建议用 std::unique_ptr<T[]> 或 C++17 的 std::shared_ptr 改进。