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

推荐订阅源

Forbes - Security
Forbes - Security
T
Tailwind CSS Blog
Hugging Face - Blog
Hugging Face - Blog
Blog — PlanetScale
Blog — PlanetScale
WordPress大学
WordPress大学
aimingoo的专栏
aimingoo的专栏
Y
Y Combinator Blog
U
Unit 42
I
InfoQ
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
V
Visual Studio Blog
B
Blog RSS Feed
Vercel News
Vercel News
F
Fortinet All Blogs
Know Your Adversary
Know Your Adversary
T
Troy Hunt's Blog
博客园 - 【当耐特】
MongoDB | Blog
MongoDB | Blog
大猫的无限游戏
大猫的无限游戏
A
About on SuperTechFans
Jina AI
Jina AI
小众软件
小众软件
T
Threatpost
有赞技术团队
有赞技术团队
人人都是产品经理
人人都是产品经理
The Hacker News
The Hacker News
T
The Exploit Database - CXSecurity.com
C
CXSECURITY Database RSS Feed - CXSecurity.com
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Microsoft Azure Blog
Microsoft Azure Blog
Recent Announcements
Recent Announcements
酷 壳 – CoolShell
酷 壳 – CoolShell
Scott Helme
Scott Helme
B
Blog
腾讯CDC
Last Week in AI
Last Week in AI
P
Proofpoint News Feed
S
Schneier on Security
N
News and Events Feed by Topic
Microsoft Security Blog
Microsoft Security Blog
K
Kaspersky official blog
G
Google Developers Blog
T
Tor Project blog
PCI Perspectives
PCI Perspectives
S
Secure Thoughts
Google Online Security Blog
Google Online Security Blog
Latest news
Latest news
Google DeepMind News
Google DeepMind News
MyScale Blog
MyScale Blog
罗磊的独立博客

博客园 - 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 改进。