3

I've noticed that when I use std::shared_ptr (or any other smart pointer) a custom allocator/deleter is assigned through the ctor, which happens to be a template. My question is: how is the allocator/deleter stored and used?

Are these functors stored as a function pointer, void*, or what? Is it an indirect call, or a direct call?

Just to have more of a clear understanding of what I'm trying to ask, consider the following code:

struct SomethingAwesomeDeleter
{
public:
    void operator()(SomethingAwesome* ptr) const
    {
        // do something awesome
        delete ptr;
    }
};
typedef std::shared_ptr<SomethingAwesome> SomethingAwesomePtr;

SomethingAwesomePtr ptr{new SomethingAwesome, SomethingAwesomeDeleter{}};

How is SomethingAwesomeDeleter{} stored and used?

NOTE: I do realise std::shared_ptr is a template class, however std::shared_ptr does not have template arguments for the deleter/allocator in the class template arguments, i.e. there is no such template class as std::shared_ptr<T, Allocator, Deleter>.

jogojapan
  • 68,383
  • 11
  • 101
  • 131
miguel.martin
  • 1,626
  • 1
  • 12
  • 27
  • There is no such template class decl as you described, you are correct. But there *is* such a template-override for the `shared_ptr` constructor (there are a *boatload* of [constructor overrides](http://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr) for `shared_ptr`). Regarding the storage, I would imagine it is implementation defined, but most implementations I've seen store them as either instance members of shared_ptr or something similar. I could (and likely am) wrong on this, as I'm not familiar with whether the standard dictates actual storage details of said-objects. – WhozCraig Jan 01 '13 at 10:28

1 Answers1

3

You can store any function object in a std::function. This takes care of either storing the function pointer directly (if it is a plain function) or wrapping it inside some object. That's one possible way to implement a shared_ptr deleter without having the function type being part of the template type.

Example (untested, just to give you the idea)

// This is the struct which actually holds the shared pointer
// A shared_ptr would reference count this
template <typename T>
class shared_ptr_shared
{
    std::function<void (T*)> del_;
    T* p_;
    // other members

    template <typename Deleter>
    shared_ptr_shared (T* obj, Deleter deleter)
    : p_ (p)
    , del_ (deleter)
    {
    }

    ~shared_ptr_shared ()
    {
        if (del_) {
            del_ (p_);
        } else {
            delete p_;
        }
    }
};

You can find out more about std::function does this here: how boost::function and boost::bind work

Community
  • 1
  • 1
Anteru
  • 19,042
  • 12
  • 77
  • 121