Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does reinterpret_cast lead to undefined behavior?

I have a class template A which contains a container of pointers (T*):

template <typename T>
class A {
public:
   // ... 
private:
   std::vector<T*> data;
};

and a bunch of functions like:

void f(const A<const T>&);
void g(const A<const T>&);

Is it OK to call these functions via a cast from A<const T> to A<T>?

A<double> a;
... 
auto& ac = reinterpret_cast<const A<const double>&>(a);
f(ac);

I'm pretty sure that this code has undefined behaviour.

Is it dangerous to use such conversions in real life?

like image 402
Sergei Avatar asked May 09 '16 14:05

Sergei


People also ask

What is the point of reinterpret_cast?

The reinterpret_cast allows the pointer to be treated as an integral type. The result is then bit-shifted and XORed with itself to produce a unique index (unique to a high degree of probability). The index is then truncated by a standard C-style cast to the return type of the function.

What is the use of reinterpret_cast in C++?

reinterpret_cast is a type of casting operator used in C++. It is used to convert a pointer of some data type into a pointer of another data type, even if the data types before and after conversion are different. It does not check if the pointer type and data pointed by the pointer is same or not.

Is reinterpret_cast safe?

The reinterpret_cast operator performs potentially unsafe type casts. It is most often used to cast a pointer to a different pointer type. Casting a pointer to a different pointer and back is usually safe and yields the original value.

Does reinterpret_cast throw?

No. It is a purely compile-time construct. It is very dangerous, because it lets you get away with very wrong conversions.


1 Answers

As A<double> and A<const double> are unrelated types, it's actually unspecified (originally I thought undefined) behavior and correspondingly yes it's a bad idea to use in real life: You never know what system(s) or compiler(s) you may port to that change the behavior is strange ways.

Reference:

5.2.10/11:

An lvalue expression of type T1 can be cast to the type “reference to T2” if an expression of type “pointer to T1” can be explicitly converted to the type “pointer to T2” using a reinterpret_cast. That is, a reference cast reinterpret_cast(x) has the same effect as the conversion *reinterpret_cast(&x) with the built-in & and * operators (and similarly for reinterpret_cast(x)).

So they've redirected us to an earlier section 5.2.10/7:

An object pointer can be explicitly converted to an object pointer of a different type. ... ... Converting a prvalue of type “pointer to T1” to the type “pointer to T2” (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer value. The result of any other such pointer conversion is unspecified.

If f and g are algorithms that work on containers, the easy solution is to change them to template algorithms that work on ranges (iterator pairs).

like image 150
Mark B Avatar answered Sep 20 '22 10:09

Mark B