Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

reinterpret_cast / static_cast and undefined behavior

In a variant class I'm working on the raw storage is a char array:

alignas(/* the strictest alignment of all types of the variant */)
char storage[/* ... */];

The assignment operator is something like:

template<class X>
void operator=(const X &x)
{
  // ...code for clearing the storage and setting the tag for type X...

  new(storage) X(x);
}

while the code for getting the stored object is:

template<class X>
const X &get()
{
  // ...
  return *reinterpret_cast<X *>(storage);
  // ...
}

It seems to work but is it always well defined? I'm worried about safely dereferencing the pointer (is it allowed by the type aliasing rules?).

Are there any differences between the current implementation and

 return *static_cast<const X *>(static_cast<const void *>(storage));

Related question/answer:

https://stackoverflow.com/a/7321815/3235496 (see James Kanze's comments).


EDIT

Second question already has an answer here: C++ When should we prefer to use a two chained static_cast over reinterpret_cast

like image 606
manlio Avatar asked Feb 07 '15 11:02

manlio


1 Answers

As storage is correctly aligned, I cannot imagine where a problem could arise. The paragraph(*) 4.10 on pointer conversions says : A prvalue of type “pointer to cv T,” where T is an object type, can be converted to a prvalue of type “pointer to cv void”. The result of converting a non-null pointer value of a pointer to object type to a “pointer to cv void” represents the address of the same byte in memory as the original pointer value.

Concerning your second question, paragraph 5.2.10 on reinterpres_cast : An object pointer can be explicitly converted to an object pointer of a different type. When a prvalue v of object pointer type is converted to the object pointer type “pointer to cv T”, the result is static_cast<cv T*>(static_cast<cv void*>(v)) where cv stands for a optional const or volatile.

So this part is guaranteed per specs. More as we saw that a cast to void * should point to first byte of memory, there is no UB for my understanding of the standard ... provided compilers have same understanding ;-)

(*) Référence : Draft for current C++ specification

like image 122
Serge Ballesta Avatar answered Sep 28 '22 22:09

Serge Ballesta