std::shared_ptr 和 std::unique_ptr 构造函数之间的不对称

assymetry between std::shared_ptr and std::unique_ptr constructors

本文关键字:std ptr 不对称 之间 shared unique 构造函数      更新时间:2023-10-16

在C++03期间,我们没有unique_ptr,所以我改用了tr1::shared_ptr

现在,在 C++11 中,在这种情况下,我将替换如下调用:

tr1::shared_ptr<X> o(new X); 

std::unique_ptr<X> o(new X);

不幸的是,由于某种原因,我无法替换包含删除器的情况,其中删除器是一个函数:

void special_delete(Y *p) { ... }
tr1::shared_ptr<Y> o(new Y(), special_delete); 

std::unique_ptr<Y> o(new Y(), special_delete);  // does not compile
std::unique_ptr<Y, std::function<void(Y*)> > o(new Y(), special_delete);  // this compiles

为什么会这样? 有没有一种同构的方法可以用unique_ptr构造函数替换所有shared_ptr构造函数?

我已经创建了这个,但我对此并不满意。

template <class Y>
using unique_ptr_with_deleter = std::unique_ptr<Y, std::function<void(Y*)> >;
unique_ptr_with_deleter<Y> o(new Y(), special_delete);  // this compiles

shared_ptr模板类型擦除删除程序。对于您想要的任何类型的删除程序,只有一种类型的shared_ptr<T>。这是一个非常重量级(且昂贵(的工具。

相比之下,unique_ptr使删除程序成为类型的一部分,因此它没有动态调用开销。unique_ptr<T, D>几乎和原始指针一样便宜。

请注意,您可以从任何删除程序类型的unique_ptr<T, D>右值构造shared_ptr<T>D


对您的解决方案的随机评论:这两种解决方案都不是很好。使用函数指针作为删除器不必要地使删除器成为unique_ptr状态的动态部分。std::function情况更糟,使用整个类型擦除虚拟调度机制进行删除 - 请记住,您静态知道如何删除!

更好的解决方案是通过编写自己的类型使删除器成为类型的一部分,而不是值的一部分:

struct YDeleter { void operator()(Y* p) { special_delete(p); } };
std::unique_ptr<Y, YDeleter> p(new Y);   // or presumaby some special factory

这样,整个删除逻辑在编译时是已知的,并且可以尽可能多地内联,而无需额外的函数调用间接寻址。

您应该提供删除器类型

std::unique_ptr<Y, decltype(&special_delete)> o{new Y{}, &special_delete};

请注意,用std::unique_ptr<X> o(new X);替换tr1::shared_ptr<X> o(new X);不是一个好主意,通常不应该工作。std::unique_ptr更像是auto_ptr的替代品。