big*_*iao 27 c++ smart-pointers unique-ptr c++-standard-library c++11
先来看看什么C++入门谈到unique_ptr和shared_ptr:
$ 16.1.6.效率和灵活性
我们可以确定
shared_ptr不将删除器作为直接成员,因为删除器的类型直到运行时才知道.因为删除器的类型是a
unique_ptr类型的一部分,所以删除器成员的类型在编译时是已知的.删除器可以直接存储在每个unique_ptr对象中.
所以似乎shared_ptr没有直接的删除成员,但unique_ptr确实如此.然而,另一个问题的最高投票回答说:
如果将deleter作为模板参数提供(如
unique_ptr),则它是类型的一部分,您不需要在此类型的对象中存储任何其他内容.如果将deleteter作为构造函数的参数传递(如shared_ptr),则需要将其存储在对象中.这是额外灵活性的代价,因为您可以为相同类型的对象使用不同的删除器.
引用的两段完全相互矛盾,让我感到困惑.更重要的是,许多人说unique_ptr是零开销,因为它不需要将删除器存储为成员.但是,正如我们所知,unique_ptr有一个构造函数unique_ptr<obj,del> p(new obj,fcn),这意味着我们可以将删除函数传递给它,因此unique_ptr似乎已将删除函数存储为成员.真是一团糟!
Rei*_*ica 32
std::unique_ptr<T>很可能是零开销(任何理智的标准库实现).std::unique_ptr<T, D>,对于任意的D,通常不是零开销.
原因很简单:如果删除器是空的(因此是无状态的)类型(例如std::default_delete实例化),则可以使用空基优化来消除删除器的存储.
MSa*_*ers 12
似乎让你困惑的关键词是"删除器可以直接存储".但是存储类型的删除器是没有意义的std::default_delete.如果你需要一个,你可以创建一个std::default_delete{}.
通常,无需存储无状态删除程序,因为您可以按需创建它们.
Pas*_* By 11
Angew的回答非常彻底地解释了发生了什么.
对于那些好奇的事情,看起来如何
template<typename T, typename D, bool Empty = std::is_empty_v<D>>
class unique_ptr
{
T* ptr;
D d;
// ...
};
template<typename T, typename D>
class unique_ptr<T, D, true> : D
{
T* ptr;
// ...
};
Run Code Online (Sandbox Code Playgroud)
其中专门用于空删除并利用空基优化.