|
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