
On Tue, Mar 21, 2017 at 4:11 PM, Andrey Semashev
On 03/21/17 14:54, Andrey Davydov wrote:
On Tue, Mar 21, 2017 at 2:15 PM, Andrey Semashev via Boost
mailto: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
mailto: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.
Because comparing the void pointers is not safe in general. The above code in particular will probably work (although not sure if even that's guaranteed, depending on whether Base and Derived qualify as standard layout classes), but if the class hierarchy is different, that code will silently break.
I agree, I wrote this code just to demonstrate that deleter must capture pointer because it can be changed due to upcasting.
But, of course, nothing stops you from saving the state in the deleter.
struct poly_deleter { template< typename T > poly_deleter(T* p) : m_p(p), m_delete(&poly_deleter::do_delete< T >) { }
void operator() (void*) const noexcept { m_delete(m_p); }
private: template< typename T > static void do_delete(void* p) noexcept { delete static_cast< T* >(p); }
void* m_p; void (*m_delete)(void*); };
This will work even if you form std::unique_ptr
(i.e. don't have a universal base class).
Your poly_deleter implementation is the same as I used inside my smart
pointer implementation, but there is an issue with std::unique_ptr