Opened 12 years ago

Closed 9 years ago

#5381 closed Feature Requests (wontfix)

get_deleter<D>(ptr) needs D to be exactly known

Reported by: christian.kotz@… Owned by: Peter Dimov
Milestone: To Be Determined Component: smart_ptr
Version: Boost 1.45.0 Severity: Problem
Keywords: Cc:

Description

get_deleter<Base_of_D>(ptr) returns 0.

This makes efficient polymorphous COW pointer implementations internally based on shared_pointer inefficient, because it is not possible to have reference count (deleter) and pointee allocated in one memory block, as is done in boost:::make_shared. Note, COW pointer need access to the deleter for the clone function at a time later than the constructor.

Suggestion: either supply:

template <typename T, D> void const * get_deleter_raw(shared_ptr<T> const & ptr);

or implement

Base_of_D const * get_deleter<Base_of_D>(shared_ptr<T> const & ptr)

returning pointer to ptrs deleter of type D (using dynamic_cast?) if B is a virtual class, (maybe using trait has_virtual_destructor)

Change History (5)

in reply to:  description comment:1 by Steven Watanabe, 12 years ago

Replying to christian.kotz@…:

get_deleter<Base_of_D>(ptr) returns 0.

This makes efficient polymorphous COW pointer implementations internally based on shared_pointer inefficient, because it is not possible to have reference count (deleter) and pointee allocated in one memory block, as is done in boost:::make_shared. Note, COW pointer need access to the deleter for the clone function at a time later than the constructor.

I don't understand. If you want to make something like make_shared, you should only need to access the deleter when you're constructing the object. At this point, you need to know the exact type of the deleter anyway. Actually, though, I don't see what you want to do that can't be handled by just using make_shared.

comment:2 by christian.kotz@…, 12 years ago

For a copy on write pointer it is not sufficient to use the actual type in the constructor only, where it is known, a la make_shared. On dereference (not construction time) it may be necessary to lazily clone (create a copy) of the pointee. In this case splicing must be avoided, so even if we have a shared_ptr<Base> which has been constructed from a make_shared<Derived> invokation the actual pointee carrier must be cloned (Derived not Base!).

here some code fragments, which sketch the "deleter"

class Carrier_base {

... most omitted private:

virtual Carrier_base *clone() = 0;

};

template <typename T, typename A = ::std::allocator<T> > class Carrier :

private A::template rebind<T>::other

{ ... most ommitted

typedef typename A::template rebind<T>::other allocator_type;

template <typename Other_A, typename... Args> static Carrier<T,A> * create(Other_A allocator, Args... args);

T * address() const;

private:

template <typename Other_A, typename... Args> explicit Carrier(Other_A allocator, Args... args);

Carrier<T,A> * clone() const{ override

Carrier<T,A> * result = allocate(1,0); try {

new (allocator_type(*this)) Carrier<T,A>(*this);

} catch(...) {

deallocate(result); throw;

} return result;

}

};

If I only allow construction in a make_shared like fashion, I know on clone time that only a class derived from Carrier_base can be the deleter. This is sufficient to invoke cloning. The actual Carrier<X> need not and cannot be in general be known. Note COW pointer is not a ::boost::shared_ptr but privatrely inherits from one or has a private member.

comment:3 by anonymous, 12 years ago

A solution could be to expose some internals to derived classes of ::boost::shared_ptr via protected, not private access control. This will on one side not endanger usage of shared_ptr, while giving implementations based on shared_ptr access (implementation is inherited via non public, e.g. private inheritance).

comment:4 by christian.kotz@…, 12 years ago

remark: Carrier<T,A> has the same function for the COW_ptr as boost::details::sp_ms_deleter in boost::make_shared

comment:5 by Peter Dimov, 9 years ago

Resolution: wontfix
Status: newclosed

Given its age, this ticket is probably no longer relevant. Still, there is now an undocumented accessor, void * _internal_get_untyped_deleter() const, which can be used. It's not very likely to be provided as part of the public interface though.

Note: See TracTickets for help on using tickets.