Domanda

Sorry about the title, I couldn't come with a better one.

Suppose that I have a class with special delete semantics, which needs to call a function instead of been deleted by delete, let's call it releaseable_object:

struct releaseable_object
{
    releaseable_object() : dummy_ptr(new int) {}
    void Release()
    {
        std::cout << "Releasing releaseable object\n";
        delete dummy_ptr;
    }
    int *const dummy_ptr;
};

And this releaseable_object is the base class of a bunch of other objects, each of them constructed by a factory which only returns pointers.

I'm trying to wrap each class into a std::unique_ptr with a custom deleter which call the releaseable_object::Release() function, so I've created a helper struct to handle some of the generic stuff:

// std::is_base_of<releaseable_object, T>::value must be true
template <typename T> struct Managed
{
    using type = T;
    static void deleter(type *object)
    {
        std::cout << "Release!\n";
        object->Release();
    };
    using pointer = std::unique_ptr<T, decltype(deleter)>;
};

And then, a bunch of derived classes which does all the specific initializations and calls to te factory:

struct ManagedA : Managed<A>
{
    using base = Managed<A>;
    using base::pointer;
    using base::deleter;
    ManagedA(/* lots of parameters */) :
        m_pointer(nullptr, deleter)
    {
        // do A specific stuff...
        A *a = factory::CreateA(/* lots of parameters */);
        // more A specific stuff...

        // wrap the pointer:
        m_pointer.reset(a);
    }
    pointer m_pointer;
};

If I try to compile the code above, it complains about the unique_ptr (demo here), I don't know what I'm doing wrong there, the error is about the instantiation of a tuple (the complete error log is in the ideone demo):

tuple: In instantiation of ‘struct std::_Head_base<1u, void(A*), false>’:
tuple:229:12:   recursively required from ‘struct std::_Tuple_impl<1u, void(A*)>’
tuple:229:12:   required from ‘struct std::_Tuple_impl<0u, A*, void(A*)>’
tuple:521:11:   required from ‘class std::tuple<A*, void(A*)>’
bits/unique_ptr.h:127:57:   required from ‘class std::unique_ptr<A, void(A*)>’

If I get rid of the m_pointer member then the compilation succeeds. I'm pretty lost with this, I'll be grateful of any hints about how to fix the compilation error.

Thanks for your attention.

È stato utile?

Soluzione

The problem is that decltype(deleter) is a function type instead of a pointer-to-function type. Changing the pointer declaration to

using pointer = std::unique_ptr<T, decltype(deleter)*>; // or spell out void(*)(T*)

will fix it.

Be aware that a function object type is usually preferable to a function pointer type for a unique pointer deleter, since the function pointer must be stored in the object itself. i.e.,

sizeof(std::unique_ptr<foo*,void(*)(foo*)>) == sizeof(foo*) + sizeof(void(*)(foo*))

but most implementations will take advantage of the Empty Base Optimization if you use an empty deleter type:

struct deleter_type {
  void operator () (foo*) {
    // ...
  }
};
sizeof(std::unique_ptr<foo*,deleter_type>) == sizeof(foo*)

Here's how your sample code would be written using a deleter type..

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top