Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

should I use it or static_cast<void*> then static_cast<myType*> to avoid reinterpret_cast?

I have seen people suggest using static_cast<SomeType*>(static_cast<void*>(p)) rather than reinterpret casting.

I don't understand why this is better, can someone explain?

For the sake of argument here is an example scenario where reinterpret_cast is needed:

DWORD lpNumberOfBytes;
ULONG_PTR lpCompletionKey;
LPOVERLAPPED lpOverlapped;
GetQueuedCompletionStatus(myHandle, &lpNumberOfBytes, &lpCompletionKey, &lpOverlapped, 0);
if(lpCompletionKey == myCustomHandlerKey){
    auto myObject = reinterpret_cast<MyObject*>(lpOverlapped);  //i know this is really a MyObject
}

This is what I have heard suggested:

auto myObject = static_cast<MyObject*>(static_cast<void*>(lpOverlapped));

Edit: I origionally started my question with In the comments section "asdf" suggests using static_cast instead of reinterpret_cast here http://blogs.msdn.com/b/vcblog/archive/2014/02/04/challenge-vulnerable-code.aspx but in retrospect the fact that my question came from there is irrelevant.

like image 846
odinthenerd Avatar asked Feb 05 '14 09:02

odinthenerd


2 Answers

§5.2.10 describes the legal mappings that reinterpret_cast can perform, and specifies that “No other conversion can be performed”.

The conversion relevant for your example is /7:

A pointer to an object can be explicitly converted to a pointer to a different object type. When a prvalue v of type “pointer to T1” is converted to the type “pointer to cv T2”, the result is static_cast<cv T2*>(static_cast<cv void*>(v)) if both T1 and T2 are standard-layout types … and the alignment requirements of T2 are no stricter than those of T1. [emphasis mine]

The result of the conversions of any other pointer to object types is “unspecified”.1

This is one of two reasons why reinterpret_cast is dangerous: its conversion is only well-defined for a subset of pointer to object types, and compilers usually offer no diagnostics about accidental misuse.

The second reason is that the compiler doesn’t even check whether the mapping you are trying to perform is legal in the first place, and which of the many (semantically completely different) mappings is going to be performed.

Better to be explicit and tell the compiler (and the reader) which the intended conversion is that you want to perform. That said, asdf’s comment isn’t quite correct, because not all conversions that you might want to perform via reinterpret_cast are equivalent to using static_cast<void*> followed by a static_cast to the target type.


1 Aside: In a nutshell (and slightly simplified), a “standard layout type” is a type (or array of type) which doesn’t have virtual functions or mixed member visibility, and all its members and bases are also standard layout. The alignment of a type is a restriction on the addresses in memory at which it may be located. For example, many machines require that doubles are aligned at addresses divisible by 8.

like image 146
Konrad Rudolph Avatar answered Oct 28 '22 18:10

Konrad Rudolph


asdf explained it quite well, even if concisely in the linked post.

because the compiler doesn't know CustomImage derives from Image at this point in the program.

Personally I can't be bothered to download rubbish from msdn just to dig in and answer the question. After all it is a coding challenge, you are supposed to figure it out.

My rules for casting in C++ are:

  1. use C++ style casts xx_cast<T*> and not C-style (T*), for explicit is better than implicit.
  2. only use reinterpret cast when you really really mean it.
  3. if you do use reinterpret_cast<T*> make sure that cast/uncast are exact mirror, e.g.:

.

T* obj = ...;
void* tmp = reinterpret_cast<void*> obj;
T* ref = reinterpret_cast<T*> tmp;  // T* obj --> T* ref

Here, you must make sure that obj and ref are same exact type, including const qualifiers, class derivation, alignment, type of memory (embedded), absolutely anything you can think of.

like image 26
Dima Tisnek Avatar answered Oct 28 '22 17:10

Dima Tisnek