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: | 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)
comment:1 by , 12 years ago
comment:2 by , 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 , 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 , 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 , 9 years ago
Resolution: | → wontfix |
---|---|
Status: | new → closed |
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.
Replying to christian.kotz@…:
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.