How does a shared_ptr store deleter?

有些话、适合烂在心里 提交于 2019-12-23 07:46:13

问题


I can't understand how a shared_ptr can store the deleter that I gave to it.

Initially, using a shared_ptr<int>, i thought it might use an std::function<void(int*)>, but i can give, as a deleter, any kind of function (or callable objects), as long as the first parameter is a int*.

How can shared_ptr do this?

I'm sorry if this is a silly question, I'm new to C++, forgive me!

Edit: The question is: how can I do something like that? What should I use? Any example? Or it is a very advanced topic?


回答1:


The deleter, as well as the allocator, are type-erased. The shared pointer manages a dynamically allocated, private, templated control object, which is accessed through a polymorphic base and which stores all the type-specific state and functionality.

The implementation of std::function uses similar ideas, since it is also a type-erasing dynamic manager class, but both are typically implemented entirely separately.

The upshot is that both classes are comparatively "expensive" and should only be used when they are genuinely necessary. Otherwise, cheaper, non-polymorphic non-dynamic solutions are usually preferable.




回答2:


I can give, as a deleter, any kind of function (or callable objects), as long as the first parameter is a int*.

No, not really. The std::shared_ptr constructor has the following contract, found in section 20.8.2.2.1 ([util.smartptr.shared.const]):

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);

Requires: p shall be convertible to T*. D shall be CopyConstructible. The copy constructor and destructor of D shall not throw exceptions. The expression d(p) shall be well formed, shall have well defined behavior, and shall not throw exceptions. A shall be an allocator (17.6.3.5). The copy constructor and destructor of A shall not throw exceptions.

Effects: Constructs a shared_ptr object that owns the object p and the deleter d. The second and fourth constructors shall use a copy of a to allocate memory for internal use.

Postconditions: use_count() == 1 && get() == p.

Throws: bad_alloc, or an implementation-defined exception when a resource other than memory could not be obtained.

Exception safety: If an exception is thrown, d(p) is called.

This requirement is a lot stronger than that the first parameter of the deleter must be the right type. It has to be the only parameter (without a default argument), such that d(p) is legal. This is slightly more flexible than std::function<void (int*)>, because the return type can be anything, but it's also more constrained with respect to exception guarantees.

If your compiler doesn't catch you when you provide a deleter with multiple required parameters, the standard library implementation is doing something rather wrong.

As far as how to implement it, take advantage of the fact that it must be CopyConstructible. For example, the following lambda should work pretty nicely, and be assignable to std::function<void(void)> (the CopyConstructible guarantee ensures that capture by value works):

[d, p] { d(p); }


来源:https://stackoverflow.com/questions/25655145/how-does-a-shared-ptr-store-deleter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!