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@lists.boost.org> 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@gmail.com> 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