C++ std::unique_ptr 和 std::shared_ptr 都支持自定义删除器(deleter)

在 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 改进。
posted @ 2025-05-23 13:35  double64  阅读(282)  评论(0)    收藏  举报