#10798 closed Bugs (wontfix)
boost::movelib::unique_ptr resolves typedef pointer with the deletor's
Reported by: | Owned by: | Ion Gaztañaga | |
---|---|---|---|
Milestone: | To Be Determined | Component: | move |
Version: | Boost 1.57.0 | Severity: | Problem |
Keywords: | Cc: |
Description
Hello,
as part of a project which entails adding some sort of virtuality in shared memory, we are using boost::interprocess::unique_ptr
extensively; this, starting from 1.57.0, maps directly to boost::movelib::unique_ptr
.
I am providing a short example that exposes the problem (see attachment).
We use a generic deleter which is non-virtual and takes a pointer to a common base class for destruction+deallocation with a custom allocator. The deleter must have a "typedef ... pointer
" member, since it needs to work also with boost::interprocess::shared_ptr
.
However, the current implementation of unique_ptr has also a member "typedef pointer
" which indirectly resolves to Deleter::pointer. That means that unique_ptr<Derived>::pointer
≡ Deleter::pointer
≡ Base
.
Since e.g. unique_ptr::operator->()
or unique_ptr::get()
have a return type of type "pointer
", each use of them effectively returns a pointer to the base class, which then needs manual static or dynamic casting.
I am providing also the patch we are currently using to work around the issue. Of course, this is just a quick hack and not suitable for Boost, but it helps to pinpoint the problem.
Attachments (2)
Change History (6)
by , 8 years ago
Attachment: | boost-movelib-unique_ptr-deleter-issue.cc added |
---|
by , 8 years ago
Attachment: | 003-move-unique_ptr-pointer-type.patch added |
---|
Temporary workaround patch
comment:1 by , 8 years ago
boost::interprocess:unique_ptr was never designed for this use case, at least, not on purpose. It was designed to be nearly-standard compatible and compatible with managed_unique_ptr, which defines a deleter with a pointer typedef, defining a smart pointer to the element_type. Couldn't a new unique_ptrdeleter that derives from your deleter and defines pointer to be a pointer to T, solve the issue?
comment:2 by , 8 years ago
Unfortunately not, since the deleter I wrote uses a field of the base class to determine the runtime type of the object, and resolves a call to the right destructor (plus, deallocates memory with the right custom allocator). This is needed since we have no virtuality in objects of classes that need to be stored in shared memory.
In other words, I need to use just a deleter for the whole hierarchy of classes, and thus its pointer member needs to be the base type. We're rolling out our handmade version of virtuality, with virtual tables and all that goes with them.
What I find counter-intuitive from a design standpoint, is that:
- be it that we have classes Derived < Base.
- given a Deleter with a member "pointer" as a typedef to Base.
- defining a unique_ptr<Derived, Deleter> and invoking ::get() results in a pointer to Base being returned.
What is the technical reason of having the pointer typedef of the unique_ptr using the pointer member of the deleter, instead than rebinding it to allow upcasts?
comment:3 by , 8 years ago
Resolution: | → wontfix |
---|---|
Status: | new → closed |
The reason is that the standard mandates that:
en.cppreference.com/w/cpp/memory/unique_ptr
pointer std::remove_reference<Deleter>::type::pointer if that type exists, otherwise T*
boost::movelib::unique_ptr is an implementation of the standard unique_ptr for boost. The Interprocess implementation had definitely a bug because it was also trying to implement the standard.
I think you can workaround it with a new deleter that inherits from your polymorphic deleter that just forwards it. Something like (simplified example):
template<class Derived> struct new_deleter : public old_deleter { typedef my_pointer<Derived> pointer; void operator()(pointer p) { old_deleter::operator()(p); } //Call polymorphic deleter };
comment:4 by , 8 years ago
Thanks, but then it wouldn't work with upcasting (and downcasting too). I would end up with a shared_ptr<Derived, new_deleter<Derived>>
which is not automatically convertible to a shared_ptr<Base, new_deleter<Base>>
.
Small example showing the compilation error