首先看一下C 底漆对unique_ptr
和shared_ptr
的说法:
$ 16.1.6。效率和灵活性
我们可以确定
shared_ptr
不会将Deleter作为直接成员,,因为直到运行时间才知道deleter的类型。由于eleter的类型是
unique_ptr
类型的一部分,因此在编译时已知DELETER成员的类型。 deleter可以直接存储在每个unique_ptr
对象中。
因此,shared_ptr
似乎没有DELERE的直接成员,但是unique_ptr
可以。但是,另一个问题的顶级答案说:
如果将eLeter作为模板参数(如
unique_ptr
中(提供,则它是类型的一部分,您不需要在此类型的对象中存储任何其他内容。如果将deleter作为构造函数的参数传递(如shared_ptr
中(,则需要将其存储在对象中。这是额外灵活性的成本,因为您可以将不同的删除器用于相同类型的对象。
这两个引用的段落完全矛盾,这使我感到困惑。更重要的是,许多人说unique_ptr
的开销为零,因为它不需要存储Deleter作为会员。但是,众所周知,unique_ptr
具有unique_ptr<obj,del> p(new obj,fcn)
的构造函数,这意味着我们可以将deleter传递给它,因此unique_ptr
似乎已将Deleter存储为成员。真是一团糟!
std::unique_ptr<T>
很可能是零偏头(具有任何SANE标准图形实现(。std::unique_ptr<T, D>
,用于任意D
,并非一般零交叉。
原因很简单:如果是空的(如std::default_delete
实例化(,则可以使用空基本优化来消除eleter的存储。
似乎混淆您的密钥短语是"直接存储 deleter 可以直接存储"。但是,存储std::default_delete
类型的删除毫无意义。如果需要,则可以将其创建为std::default_delete{}
。
通常,无需存储无状态删除器,因为您可以按需创建它们。
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;
// ...
};
专门用于空删除器并利用空基础优化的优势。
简短介绍:
unique_ptr can 介绍一些小开销,但不是因为deleter,而是因为当您从IT迁移时,必须将其设置为null,如果您使用原始指针,则可以离开旧的指针在容易出现的错误状态下,它仍然指向以前指向的位置。显然,智能优化器可以优化,但不能保证。
回到eleter:
其他答案是正确的,但详尽。因此,这是提及EBO或其他复杂术语的简化版本。
如果DELERE为空(没有状态(,则不需要将其保存在unique_ptr中。如果需要,则可以在需要时构造它。您需要知道的只是eleter类型(这是unique_ptr的模板参数之一(。
对于Exaple,请考虑按照代码,而不是根据无状态对象的需求证明简单的创建。
#include <iostream>
#include <string>
#include <string_view>
template<typename Person>
struct Greeter{
void greet(){
static_assert(std::is_empty_v<Person>, "Person must be stateless");
Person p; // Stateless Person instance constructed on demand
std::cout << "Hello " << p() << std::endl;
}
// ... and not kept as a member.
};
struct Bjarne{
std::string_view operator()(){
return "Bjarne";
}
};
int main() {
Greeter<Bjarne> hello_bjarne;
hello_bjarne.greet();
}