0
template <class T> class Foo {};

class Manager {
    std::unordered_map<size_t, std::unique_ptr<std::vector<void *>>> _mFoos;

public:
    template <class T> void addFoo(Foo<T> &foo) {
        int x = typeid(T).hash_code();

        // Safe ? :
        auto &p = *(reinterpret_cast<std::unique_ptr<std::vector<Foo<T>>> *>(&_mFoos[x]));

        if (p == nullptr) {
            p.reset(new std::vector<Foo<T>>);
        }

        auto &foos = *p;
        foos.push_back(foo);
    };

    template <class T> Foo<T> &getFoo(int index) {
        int x = typeid(T).hash_code();
        auto it = _mFoos.find(x);

        auto &foos = *(reinterpret_cast<std::vector<Foo<T>> *>(it->second.get()));

        return foos[index];
    };
};

Is it safe and portable to reinterpret_cast a unique_ptr< T > in a unique_ptr< T2 > if T and T2 are two different types ? Does they have the same size and the same bit pattern ?

Johnmph
  • 3,391
  • 24
  • 32

3 Answers3

3

No.

Casting between unrelated types (and different template instances are unrelated types) is undefined behavior according to the strict aliasing rule.

Šimon Tóth
  • 35,456
  • 20
  • 106
  • 151
  • Ok thank you, so instead using unique_ptr, can I use void * (and manage pointer's ownership myself), is it ok with the strict aliasing rule ( std::vector * -> void * -> std::vector * ) ? – Johnmph Jul 09 '15 at 15:06
  • `unique_ptr` isn't the problem here at all :-) As noted by others, it has no impact on the casting behavior. If you have two distinct types then it makes no sense to store them in a single vector. Especially if you allow a generic `get()` method. – Šimon Tóth Jul 09 '15 at 15:11
  • The getFoo method is also a templated method, I know all the types I need at the compile time, it's why I want to avoid any virtual method / dynamic polymorphism, All I need to have is a container (unordered_map) which holds different types but because it's impossible, I create a new object of a type then cast its pointer to a generic type (void *) to save it into container but each time I use this object I know its true type because I access it only by a templated method which is called with the correct type. – Johnmph Jul 09 '15 at 15:34
  • And for the call of the correct destructors for the contained objects when unordered_map is destroyed, I save a destructor wrapper function address also in another unordered_map. – Johnmph Jul 09 '15 at 15:35
2

(sidenote Apparently I'm required to state the obvious: don't reinterpret_cast, please. See When should static_cast, dynamic_cast, const_cast and reinterpret_cast be used?)

With shared_ptr you could use

For unique_ptr you'll have to do the conversion with move. C++17 implements the converting constructor:

template<class U> explicit unique_ptr( U p );

See http://en.cppreference.com/w/cpp/memory/unique_ptr/unique_ptr

2-4) in the specialization for arrays behave the same as the constructors that take a pointer parameter in the primary template except that they will only participate in overload resolution if either U is the same type as pointer, or pointer is the same type as element_type* and U is some pointer type V* such that V(*)[] is implicitly convertible to element_type(*)[].

Community
  • 1
  • 1
sehe
  • 374,641
  • 47
  • 450
  • 633
0

The normal rules apply; you can only reinterpret_cast the results of .get() to a type if the unique_ptr was constructed with a pointer of that type.

The behaviour of casting to any other type is undefined.

P45 Imminent
  • 8,319
  • 4
  • 35
  • 78