May be the best solution will be implement type_erased_unique_ptr
Re-posting here as I replied direct to Andrey by mistake: publicly inheriting from std::unique_ptr<T, type_erased_deleter> and defining own set of constructors. What do you think about this? I think that's reasonable. The conversion constructor can take care of marshalling the pointer and deleter into the polymorphic deleter. Again though, is this necessary? Won't a partial specialisation take care of this? The c++ standard mandates that specialisations of std:: template classes must provide the services specified at a *minimum*. It does not prevent them from offering more services (such as a conversion constructor). By which I mean, this is legal, AFAIK: namespace std { template<class T> struct unique_ptr<T, ::notstd::polymorphic_deleter> { template<class U, class D, std::enable_if_t<not std::is_same<D, ::notstd::polymorphic_deleter>::value>* = nullptr> unique_ptr(std::unique_ptr<U, D>&& other) { // ... } // etc... implement the rest of unique_ptr's interface }; } On 21 March 2017 at 12:54, Andrey Davydov via Boost <boost@lists.boost.org> wrote:
On Tue, Mar 21, 2017 at 2:15 PM, 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.
Why this code is very unsafe? If change `ptr` to `shared_ptr` this will become perfectly valid and widely used pattern.
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)); }
What is `D`? If it is std::default_delete<T> then function result type will be std::unique_ptr<U, std::default_delete<T>> and unlikely this type is very useful (even if it compiles).
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.
May be I doesn't understand what TONGARI J suggested, but how can `unique_ptr<T, void(*)(T*)>` hold stateful deleter?
-- Andrey Davydov
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/ mailman/listinfo.cgi/boost