我知道std::unique_ptr
和std::shared_ptr
是满足不同需求的不同类,因此问哪一个更好主要是一个不恰当的问题。
但是,关于它们的内容和性能,在不考虑两个智能指针的不同语义的情况下,我有些怀疑我想要澄清。
我的理解是,std::unique_ptr
包含原始指针作为其唯一的成员变量,并将删除器(如果给定任何自定义删除器)存储为类型的一部分;而std::shared_ptr
将原始以及指向包含自定义删除器的动态分配块的指针存储在成员变量中, 以及强弱计数器。
斯科特·迈耶斯(Scott Meyers)在《有效的现代C++》中强调了两个智能指针所需的大小差异(以及一般性能的差异),但是我很想说,一旦std::unique_ptr
被提供函数指针作为自定义删除器,它就会变得和std::shared_ptr
一样大, 其大小不会随自定义删除程序而增加。
从那里,我会推断,使用函数指针作为std::unique_ptr
的自定义删除器基本上消除了这个智能指针在大小/性能方面相对于另一个的优势。
是这样吗?
确实(我怀疑这是标准所要求的)是
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
将删除程序就地存储,即存储在堆栈上。调用此删除程序可能比与 pointee 和引用计数一起位于堆分配块中的删除程序更快。std::unique_ptr
也不会键入擦除删除程序。烘焙到类型中的 lambda 肯定比隐藏删除程序类型所需的间接寻址更有效,如std::shared_ptr
。