Boost logo

Boost :

Subject: Re: [boost] [smart_ptr] Is there any interest in unique_ptr with type erased deleter?
From: Richard Hodges (hodges.r_at_[hidden])
Date: 2017-03-21 11:22:53


Here's a first cut of a polymorphic deleter (which at least allows you to
spell the name of the unique_ptr<A> in the example). It's not optimally
efficient, but a little SFO should do it.

#include <memory>
#include <iostream>

namespace notstd {

    class polymorphic_deleter
    {
        struct concept
        {
            virtual void impl_call() const = 0;
        };

        template<class T, class Deleter>
        struct model final
            : concept
        {
            model(T *p, Deleter del)
                : p_(p)
                , del_(std::move(del)) {}

            void impl_call() const
            {
                del_(p_);
            }

            T *p_;
            Deleter del_;
        };

        std::unique_ptr<concept> impl_;

        template<class T, class Del>
        static auto make_model(T* p, Del&& del)
        {
            using deleter_type = std::decay_t<Del>;
            using pointer_type = T;
            return std::make_unique<model<pointer_type, deleter_type>>
( p, std::forward<Del>(del) );
        };

    public:

        template<class T, class Del>
        polymorphic_deleter(T* p, Del&& del)
            : impl_(make_model(p, std::forward<Del>(del)))
        {}

        void operator()(void*) const {
            impl_->impl_call();
        }

    };

    template<class T, class...Args>
    auto make_polymorphic_unique(Args&&...args)
    {
        auto pt = std::make_unique<T>(std::forward<Args>(args)...);
        auto del = polymorphic_deleter(pt.get(), std::default_delete<T>());
        return std::unique_ptr<T, polymorphic_deleter>(pt.release(),
std::move(del));
    };

}

struct A
{
    ~A() { std::cout << "deleting A\n"; }
};

struct B : A
{
    ~B() { std::cout << "deleting B\n"; }
};

int main()
{
    auto pb = notstd::make_polymorphic_unique<B>();
    auto pa = std::unique_ptr<A, notstd::polymorphic_deleter>(std::move(pb));
    pa.reset();
}

On 21 March 2017 at 12:15, Andrey Semashev via Boost <boost_at_[hidden]>
wrote:

> On 03/21/17 12:54, Andrey Davydov via Boost wrote:
>
>> On Tue, Mar 21, 2017 at 12:00 PM, Richard Hodges <hodges.r_at_[hidden]>
>> wrote:
>>
>> What is required, more than simply creating a type-erased deleter?
>>>
>>
>> Also deleter must capture pointer, because pointer which was passed to
>> constructor can differ from the pointer which will be deleted. For
>> example,
>>
>> struct Base { /* ... */ };
>> struct Derived : Base { /* ... */ };
>>
>> ptr<Derived> p1(new Derived);
>> void * raw_p1 = p1.get();
>> ptr<Base> p2 = std::move(p1);
>> void * raw_p2 = p2.get();
>> assert(raw_p1 != raw_p2);
>>
>
> The above piece of code strikes me as very unsafe and better be avoided in
> the first place. Designing new tools to handle this case is IMHO misguided.
>
> Now, I can understand the need to perform casts on smart-pointers, but
> they should still provide some level of safety, at least the same level
> that is provided by pointer casts in the core language. But supporting
> casts should not require a new smart-pointer. And indeed it doesn't:
>
> template< typename U, typename T, typename D >
> std::unique_ptr< U, D > static_pointer_cast(
> std::unique_ptr< T, D >&& p)
> {
> D d = p.get_deleter();
> return std::unique_ptr< U, D >(
> static_cast< U* >(p.release()),
> std::move(d));
> }
>
> The other part of your proposal, which is polymorphic behavior with a
> deleter knowing the type to call the destructor on, can be solved by a
> custom deleter. I'm not sure a generalized version of such deleter would
> have a large demand, given that there is the alternative TONGARI J
> suggested, but I'm not opposed to a proposal.
>
>
>
> _______________________________________________
> Unsubscribe & other changes: http://lists.boost.org/mailman
> /listinfo.cgi/boost
>


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk