Boost C++ Libraries: Ticket #10798: boost::movelib::unique_ptr resolves typedef pointer with the deletor's https://svn.boost.org/trac10/ticket/10798 <p> Hello, </p> <p> as part of a project which entails adding some sort of virtuality in shared memory, we are using <code>boost::interprocess::unique_ptr</code> extensively; this, starting from 1.57.0, maps directly to <code>boost::movelib::unique_ptr</code>. </p> <p> I am providing a short example that exposes the problem (see attachment). </p> <p> 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 "<code>typedef ... pointer</code>" member, since it needs to work also with <code>boost::interprocess::shared_ptr</code>. </p> <p> However, the current implementation of unique_ptr has also a member "<code>typedef pointer</code>" which indirectly resolves to Deleter::pointer. That means that <code>unique_ptr&lt;Derived&gt;::pointer</code> ≡ <code>Deleter::pointer</code> ≡ <code>Base</code>. </p> <p> Since e.g. <code>unique_ptr::operator-&gt;()</code> or <code>unique_ptr::get()</code> have a return type of type "<code>pointer</code>", each use of them effectively returns a pointer to the base class, which then needs manual static or dynamic casting. </p> <p> 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. </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/10798 Trac 1.4.3 Matteo Settenvini <matteo.settenvini@…> Mon, 17 Nov 2014 12:41:21 GMT attachment set https://svn.boost.org/trac10/ticket/10798 https://svn.boost.org/trac10/ticket/10798 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">boost-movelib-unique_ptr-deleter-issue.cc</span> </li> </ul> <p> Small example showing the compilation error </p> Ticket Matteo Settenvini <matteo.settenvini@…> Mon, 17 Nov 2014 12:41:48 GMT attachment set https://svn.boost.org/trac10/ticket/10798 https://svn.boost.org/trac10/ticket/10798 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">003-move-unique_ptr-pointer-type.patch</span> </li> </ul> <p> Temporary workaround patch </p> Ticket Ion Gaztañaga Mon, 24 Nov 2014 21:30:14 GMT <link>https://svn.boost.org/trac10/ticket/10798#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/10798#comment:1</guid> <description> <p> 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? </p> </description> <category>Ticket</category> </item> <item> <author>Matteo Settenvini <matteo.settenvini@…></author> <pubDate>Tue, 25 Nov 2014 08:52:27 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/10798#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/10798#comment:2</guid> <description> <p> 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. </p> <p> 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. </p> <p> What I find counter-intuitive from a design standpoint, is that: </p> <ul><li>be it that we have classes Derived &lt; Base. </li><li>given a Deleter with a member "pointer" as a typedef to Base. </li><li>defining a unique_ptr&lt;Derived, Deleter&gt; and invoking ::get() results in a pointer to Base being returned. </li></ul><p> 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? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Ion Gaztañaga</dc:creator> <pubDate>Mon, 15 Dec 2014 16:30:53 GMT</pubDate> <title>status changed; resolution set https://svn.boost.org/trac10/ticket/10798#comment:3 https://svn.boost.org/trac10/ticket/10798#comment:3 <ul> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">wontfix</span> </li> </ul> <p> The reason is that the standard mandates that: </p> <p> en.cppreference.com/w/cpp/memory/unique_ptr </p> <pre class="wiki">pointer std::remove_reference&lt;Deleter&gt;::type::pointer if that type exists, otherwise T* </pre><p> 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. </p> <p> I think you can workaround it with a new deleter that inherits from your polymorphic deleter that just forwards it. Something like (simplified example): </p> <pre class="wiki"> template&lt;class Derived&gt; struct new_deleter : public old_deleter { typedef my_pointer&lt;Derived&gt; pointer; void operator()(pointer p) { old_deleter::operator()(p); } //Call polymorphic deleter }; </pre> Ticket Matteo Settenvini <matteo.settenvini@…> Tue, 16 Dec 2014 11:02:22 GMT <link>https://svn.boost.org/trac10/ticket/10798#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/10798#comment:4</guid> <description> <p> Thanks, but then it wouldn't work with upcasting (and downcasting too). I would end up with a <code>shared_ptr&lt;Derived, new_deleter&lt;Derived&gt;&gt;</code> which is not automatically convertible to a <code>shared_ptr&lt;Base, new_deleter&lt;Base&gt;&gt;</code>. </p> </description> <category>Ticket</category> </item> </channel> </rss>