Opened 8 years ago

Last modified 7 years ago

#11032 new Bugs

boost::offset_ptr needs explicit ctor

Reported by: stheophil@… Owned by: Ion Gaztañaga
Milestone: To Be Determined Component: interprocess
Version: Boost 1.57.0 Severity: Problem
Keywords: Cc:

Description

Both the libc++ std library implementation and the MSVC library implementation require that their pointer types can be upcast.

The list and tree data structures have a class hierarchy of node types and often seem to pass pointers to the base types (or to offset_ptr<void>) that are then upcast to the most derived types. offset_ptr has no explicit constructor that allows upcasts, only implicit ctors for downcasts.

We have patched our version of offset_ptr with this constructor:

//!Explicit constructor from other offset_ptr. Never throws.
template<class T2>
explicit offset_ptr(const offset_ptr<T2, DifferenceType, OffsetType, OffsetAlignment> &ptr
   , typename ipcdetail::enable_if_c<
   !ipcdetail::is_convertible<T2*, PointedType*>::value 
    >::type * = 0)
    : internal(ipcdetail::offset_ptr_to_offset<OffsetType>(static_cast<PointedType*>(ptr.get()), this))
 {}

Change History (3)

comment:1 by Ion Gaztañaga, 8 years ago

I can't see the problem. offset_ptr has a constructor that allows conversions:

//!Constructor from other offset_ptr. If pointers of pointee types are
//!convertible, offset_ptrs will be convertibles. Never throws.
template<class T2>
offset_ptr( const offset_ptr<T2, DifferenceType, OffsetType, OffsetAlignment> &ptr
          #ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
          , typename ipcdetail::enable_if_c< ipcdetail::is_convertible<T2*, PointedType*>::value
            && ipcdetail::offset_ptr_maintains_address<T2, PointedType>::value
          >::type * = 0
          #endif
          )
   : internal(static_cast<OffsetType>
         (ipcdetail::offset_ptr_to_offset_from_other<0>(this, &ptr, ptr.get_offset())))
{}

//!Constructor from other offset_ptr. If pointers of pointee types are
//!convertible, offset_ptrs will be convertibles. Never throws.
template<class T2>
offset_ptr( const offset_ptr<T2, DifferenceType, OffsetType, OffsetAlignment> &ptr
            , typename ipcdetail::enable_if_c< ipcdetail::is_convertible<T2*, PointedType*>::value
            && !ipcdetail::offset_ptr_maintains_address<T2, PointedType>::value
            >::type * = 0)
   : internal(static_cast<OffsetType>
      (ipcdetail::offset_ptr_to_offset<0>(static_cast<PointedType*>(ptr.get()), this)))
{}

this allows upcasting (from derived to base). Did you mean that offset_ptr does not support downcasting (from base to derived)? It does that for good safety reasons as raw pointers don't allow those conversions. Do you want this to compile?

offset_ptr<Base> pb = ...; offset_ptr<Derived>pd(p);

whereas this is a compilation error

Base *pb = ... Derived *pd = pb;

?

comment:2 by stheophil@…, 8 years ago

Yes, I want it to support downcasting. Sorry.

offset_ptr<Base> pb = ...; offset_ptr<Derived>pd(pb);

Does not have to compile because, as you say, raw pointers do not support this conversion, but

offset_ptr<Base> pb = ...; offset_ptr<Derived>pd = static_cast<offset_ptr<Derived>>(pb);

should compile and by consequence

offset_ptr<Base> pb = ...; offset_ptr<Derived>pd = (offset_ptr<Derived>)pb;

too, which just does a static_cast if I understand correctly. Both are used a lot in std::list and std::map implementations of Clang and MSVC.

comment:3 by Chris Clearwater <chris@…>, 7 years ago

Please see the table here: http://en.cppreference.com/w/cpp/concept/Allocator

The C++11 standard requires static_cast<A::pointer>(vptr) to succeed.

I have also run into this problem when trying to use my own container, which uses void_pointer to store child pointers, with Boost.Interprocess.

Note: See TracTickets for help on using tickets.