unique_ptr作为自定义删除器的函数指针是否与shared_ptr大小相同?

Is a unique_ptr equipped with a function pointer as custom deleter the same size as a shared_ptr?

我知道 std::unique_ptrstd::shared_ptr 是不同的 类 满足不同的需求,因此问哪个更好是一个不恰当的问题。

但是,关于它们的内容和性能,不考虑两个智能指针的不同语义,我有一些疑问,我想澄清一下。

我的理解是 std::unique_ptr 包含原始指针作为其唯一的成员变量,并且存储删除器(如果给出了自定义删除器)作为类型的一部分;而 std::shared_ptr 在成员变量中存储原始数据以及指向包含自定义删除器的动态分配块的指针,以及强计数器和弱计数器。

Scott Meyers,在 Effective Modern C++ 中,着重强调了两个智能指针所需的大小差异(以及一般性能差异),但我很想尽快说由于 std::unique_ptr 提供了 函数指针 作为自定义删除器,它变得和 std::shared_ptr 一样大,其大小不会随着自定义删除器的增加而增加。

从那里,我会推断使用 函数指针 作为 std::unique_ptr 的自定义删除器基本上消除了这个智能指针对另一个智能指针的优势,在size/performance.

条款

是这样吗?

是真的(我怀疑这是标准要求的)
static_assert(sizeof(std::unique_ptr<int, void(*)(int*)>) == sizeof(std::shared_ptr<int>));

但我不同意将函数指针存储为自定义删除器会使 std::unique_ptr 相对于 std::shared_ptr 的优势变得无用的结论。这两种类型都建立了非常不同的所有权语义模型,选择一种而不是另一种与性能没有太大关系,而是与您打算如何处理 pointee 实例有关。

在性能方面,std::unique_ptr 总是比 std::shared_ptr 更有效率。虽然这主要是由于后者的线程安全引用计数,但对于自定义删除器也是如此:

  • std::unique_ptr 就地存储删除器,即在堆栈上。调用此删除器可能比位于堆分配块中的删除器以及指针和引用计数更快。
  • std::unique_ptr 也不会键入擦除删除器。嵌入到类型中的 lambda 肯定比隐藏删除器类型所需的间接更有效,如 std::shared_ptr.