문제

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.

도움이 되었습니까?

해결책

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..

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top