假设我有一个带有自定义分配器和自定义删除器的shared_ptr
。
我在标准中找不到任何关于删除器应该存储在哪里的说明:它没有说自定义分配器将用于删除器的内存,也没有说它不会使用。
这是未指定的还是我遗漏了什么?
假设我有一个带有自定义分配器和自定义删除器的shared_ptr
。
我在标准中找不到任何关于删除器应该存储在哪里的说明:它没有说自定义分配器将用于删除器的内存,也没有说它不会使用。
这是未指定的还是我遗漏了什么?
C++ 11中的util.smartptr.shared.const/9:
效果: 构造一个拥有对象p和删除器d的shared_ptr对象。第二个和第四个构造函数将使用a的副本为内部使用分配内存。
第二个和第四个构造函数的原型如下:
template<class Y, class D, class A> shared_ptr(Y* p, D d, A a);
template<class D, class A> shared_ptr(nullptr_t p, D d, A a);
shared_ptr
之间复制的实现)。来自 std::shared_ptr,我们得到:
控制块是一个动态分配的对象,它包含:
而从 std::allocate_shared 中,我们得到:
template< class T, class Alloc, class... Args >
shared_ptr<T> allocate_shared( const Alloc& alloc, Args&&... args );
Alloc
来分配deleter
。n4810
§20.11.3.6 Creation [util.smartptr.shared.create]make_shared
,allocate_shared
,make_shared_default_init
和allocate_shared_default_init
重载函数,除非另有规定,否则如下所述。std::allocate_shared
应该使用Alloc
来控制块。make_shared
,而不是构造函数本身。尽管如此,我仍然可以使用成员对于小的删除者。 - L. F.std::allocate_shared
,std::make_shared
恰好在同一部分。我理解它的意思是:std::allocate_shared
应该为控制块(因此也是删除器)和 T
对象的内存分配一个 Alloc
分配。 - Paul Evans
template<class Y, class D> shared_ptr(Y* p, D d); template<class Y, class D, class A> shared_ptr(Y* p, D d, A a); template <class D> shared_ptr(nullptr_t p, D d); template <class D, class A> shared_ptr(nullptr_t p, D d, A a);
Effects: Constructs a
shared_ptr
object that owns the objectp
and the deleterd
. WhenT
is not an array type, the first and second constructors enableshared_from_this
withp
. The second and fourth constructors shall use a copy ofa
to allocate memory for internal use. If an exception is thrown,d(p)
is called.
现在,我的理解是当实现需要内存进行内部使用时,它会使用a
。这并不意味着实现必须使用这个内存来放置所有东西。例如,假设有这样一个奇怪的实现:
template <typename T>
class shared_ptr : /* ... */ {
// ...
std::aligned_storage<16> _Small_deleter;
// ...
public:
// ...
template <class _D, class _A>
shared_ptr(nullptr_t, _D __d, _A __a) // for example
: _Allocator_base{__a}
{
if constexpr (sizeof(_D) <= 16)
_Construct_at(&_Small_deleter, std::move(__d));
else
// use 'a' to allocate storage for the deleter
}
// ...
};
a
的副本来分配内存以供内部使用”?是的,它是。它从不使用除a
之外的任何方法分配内存。这个朴素的实现有很多问题,但是假设在最简单的情况下,即直接从指针构造shared_ptr
并且不会复制、移动或以其他方式引用以及没有其他复杂性时,它会切换到使用分配器。重点是,仅仅因为我们无法想象出一种有效的实现,并不能证明它在理论上不存在。我并不是说这样的实现实际上可以在现实世界中找到,只是标准似乎并没有积极禁止它。shared_ptr
在堆栈上分配内存。因此不符合标准要求。 - bartopstd::move(__d)
,并在需要复制时回退到 allocate
。 - L. F.