Why do we have reinterpret_cast in C++ when two chained static_cast can do its job?
There are things that reinterpret_cast
can do that no sequence of static_cast
s can do (all from C++03 5.2.10):
A pointer can be explicitly converted to any integral type large enough to hold it.
A value of integral type or enumeration type can be explicitly converted to a pointer.
A pointer to a function can be explicitly converted to a pointer to a function of a different type.
An rvalue of type "pointer to member of
X
of typeT1
" can be explicitly converted to an rvalue of type "pointer to member ofY
of typeT2
" ifT1
andT2
are both function types or both object types.
Also, from C++03 9.2/17:
- A pointer to a POD-struct object, suitably converted using a
reinterpret_cast
, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa.
When should static_cast, dynamic_cast, const_cast, and reinterpret_cast be used?
static_cast
is the first cast you should attempt to use. It does things like implicit conversions between types (such as int
to float
, or pointer to void*
), and it can also call explicit conversion functions (or implicit ones). In many cases, explicitly stating static_cast
isn't necessary, but it's important to note that the T(something)
syntax is equivalent to (T)something
and should be avoided (more on that later). A T(something, something_else)
is safe, however, and guaranteed to call the constructor.
static_cast
can also cast through inheritance hierarchies. It is unnecessary when casting upwards (towards a base class), but when casting downwards it can be used as long as it doesn't cast through virtual
inheritance. It does not do checking, however, and it is undefined behavior to static_cast
down a hierarchy to a type that isn't actually the type of the object.
const_cast
can be used to remove or add const
to a variable; no other C++ cast is capable of removing it (not even reinterpret_cast
). It is important to note that modifying a formerly const
value is only undefined if the original variable is const
; if you use it to take the const
off a reference to something that wasn't declared with const
, it is safe. This can be useful when overloading member functions based on const
, for instance. It can also be used to add const
to an object, such as to call a member function overload.
const_cast
also works similarly on volatile
, though that's less common.
dynamic_cast
is exclusively used for handling polymorphism. You can cast a pointer or reference to any polymorphic type to any other class type (a polymorphic type has at least one virtual function, declared or inherited). You can use it for more than just casting downwards – you can cast sideways or even up another chain. The dynamic_cast
will seek out the desired object and return it if possible. If it can't, it will return nullptr
in the case of a pointer, or throw std::bad_cast
in the case of a reference.
dynamic_cast
has some limitations, though. It doesn't work if there are multiple objects of the same type in the inheritance hierarchy (the so-called 'dreaded diamond') and you aren't using virtual
inheritance. It also can only go through public inheritance - it will always fail to travel through protected
or private
inheritance. This is rarely an issue, however, as such forms of inheritance are rare.
reinterpret_cast
is the most dangerous cast, and should be used very sparingly. It turns one type directly into another — such as casting the value from one pointer to another, or storing a pointer in an int
, or all sorts of other nasty things. Largely, the only guarantee you get with reinterpret_cast
is that normally if you cast the result back to the original type, you will get the exact same value (but not if the intermediate type is smaller than the original type). There are a number of conversions that reinterpret_cast
cannot do, too. It's used primarily for particularly weird conversions and bit manipulations, like turning a raw data stream into actual data, or storing data in the low bits of a pointer to aligned data.
C-style cast and function-style cast are casts using (type)object
or type(object)
, respectively, and are functionally equivalent. They are defined as the first of the following which succeeds:
const_cast
static_cast
(though ignoring access restrictions)static_cast
(see above), thenconst_cast
reinterpret_cast
reinterpret_cast
, thenconst_cast
It can therefore be used as a replacement for other casts in some instances, but can be extremely dangerous because of the ability to devolve into a reinterpret_cast
, and the latter should be preferred when explicit casting is needed, unless you are sure static_cast
will succeed or reinterpret_cast
will fail. Even then, consider the longer, more explicit option.
C-style casts also ignore access control when performing a static_cast
, which means that they have the ability to perform an operation that no other cast can. This is mostly a kludge, though, and in my mind is just another reason to avoid C-style casts.
Which cast to use; static_cast or reinterpret_cast?
static_cast
provided that you know (by design of your program) that the thing pointed to really is an int
.
static_cast is designed to reverse any implicit conversion. You converted to void*
implicitly, therefore you can (and should) convert back with static_cast
if you know that you really are just reversing an earlier conversion.
With that assumption, nothing is being reinterpreted - void
is an incomplete type, meaning that it has no values, so at no point are you interpreting either a stored int value "as void" or a stored "void value" as int. void*
is just an ugly way of saying, "I don't know the type, but I'm going to pass the pointer on to someone else who does".
reinterpret_cast
if you've omitted details that mean you might actually be reading memory using a type other than the type is was written with, and be aware that your code will have limited portability.
By the way, there are not very many good reasons for using a void*
pointer in this way in C++. C-style callback interfaces can often be replaced with either a template function (for anything that resembles the standard function qsort
) or a virtual interface (for anything that resembles a registered listener). If your C++ code is using some C API then of course you don't have much choice.
Should I use a C++ reinterpret_cast over a C-style cast?
The problem with C-Style casts is that they do a lot under the hood. See here for a detailed explanation: http://anteru.net/2007/12/18/200/
You should try to always use the C++-casts, makes life easier in the long run. The main problem with C-style casts in this case is that you could have written (char*)(&v)
while with reinterpret_cast
, you would need an additional const_cast
, so it's a bit safer. Plus you can easily find reinterpret_cast
with a regex, which is not possible for the C-style casts.
Which one to use when static_cast and reinterpret_cast have the same effect?
Everybody has noted that reinterpret_cast<> is more dangerous than static_cast<>.
This is because reinterpret_cast<> ignores all type information and just assigns a new type without any real processing, as a result the processing done is implementation defined (though usually the bit patterns of the pointers are the same).
The thing everybody fails to mention is that reinterpret_cast<> is a means to document your program. It tells somebody reading the code that we had to compromise something and as a result we have ended up with a dangerous cast, and be careful when you mess with this code.
Use the reinterpret_cast<> to highlight these dangerous areas in the code.
When casting from a void* there is not type information for the cast to work with.
So you are either doing an invalid cast or a casting back to the original type that was previously cast into a void*. Any other type of casting is going to end up with some undefined behavior.
This is the perfect situation to use reinterpret_cast<> as the standard guarantees that casting a pointer to void* and back to its original type using reinterpret_cast<> will work. And by using reinterpret_cast<> you are pointing out to the humans that come along afterwords that something bad is happening here.
When to use reinterpret_cast?
The C++ standard guarantees the following:
static_cast
ing a pointer to and from void*
preserves the address. That is, in the following, a
, b
and c
all point to the same address:
int* a = new int();
void* b = static_cast<void*>(a);
int* c = static_cast<int*>(b);
reinterpret_cast
only guarantees that if you cast a pointer to a different type, and then reinterpret_cast
it back to the original type, you get the original value. So in the following:
int* a = new int();
void* b = reinterpret_cast<void*>(a);
int* c = reinterpret_cast<int*>(b);
a
and c
contain the same value, but the value of b
is unspecified. (in practice it will typically contain the same address as a
and c
, but that's not specified in the standard, and it may not be true on machines with more complex memory systems.)
For casting to and from void*
, static_cast
should be preferred.
Why is it important to use static_cast instead of reinterpret_cast here?
Using static_cast is fine at the example but reinterpret_cast is not. Because reinterpret_cast is not convert vtable.
No, the problem is that the reinterpret_cast
is completely oblivious about the inheritance. It will simply return the same address unchanged1. But static_cast
knows that you're performing a downcast: i.e. casting from a base class to a derived class. Since it knows both types involved it adjusts the address accordingly, i.e., does the right thing.
Let's pretend our implementation lays out the hypothetical OVERLAPPEDEX
class that has a virtual function like this:
+------+------------+------------------+-------------+
| vptr | OVERLAPPED | AssociatedClient | ClientState |
+------+------------+------------------+-------------+
^
|
ptr
The pointer we're given points to the OVERLAPPED
subobject. reinterpret_cast
would not change that. It would only change the type. Obviously, accessing the OVERLAPPEDEX
class through this address would easily wreak havoc, because the locations of its subobjects are all wrong now!
what we believe we have when we access OVERLAPPEDEX through the pointer
+------+------------+------------------+-------------+
| vptr | OVERLAPPED | AssociatedClient | ClientState |
+------+------+-----+------+-----------+------+------+------+
| vptr | OVERLAPPED | AssociatedClient | ClientState | <- what we actually have
+------+------------+------------------+-------------+
^
|
ptr
static_cast
knows that to convert a OVERLAPPED*
to OVERLAPPEDEX*
it must adjust the address, and does the right thing:
+------+------------+------------------+-------------+
| vptr | OVERLAPPED | AssociatedClient | ClientState |
+------+------------+------------------+-------------+
^
|
ptr after static_cast
Though, if I use C-Style cast at there(not reinterpret_cast), could it also go wrong?
A C-style cast is defined as the first one of the following that succeeds:
const_cast
static_cast
static_cast
, thenconst_cast
reinterpret_cast
reinterpret_cast
, thenconst_cast
As you can see, a static_cast
is tried before reinterpret_cast
, so in this case, a C-style cast would also do the right thing.
More info
1Not guaranteed. There are very little guarantees about what happens on a reinterpret_cast
. All implementations I know of will simply give out the same address unchanged.
should I use it or static_castvoid* then static_castmyType* to avoid reinterpret_cast?
§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 toT1
” is converted to the type “pointer to cvT2
”, the result isstatic_cast<cv T2*>(static_cast<cv void*>(v))
if bothT1
andT2
are standard-layout types … and the alignment requirements ofT2
are no stricter than those ofT1
. [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 double
s are aligned at addresses divisible by 8.
Related Topics
Reasonably Portable Way to Get Top 64-Bits from 64X64 Bit Multiply
Understanding (Simple) C++ Partial Template Specialization
How to Store Different Data Types in One List? (C++)
Initial Value of Reference to Non-Const Must Be an Lvalue
Understanding Gsl::Narrow Implementation
Check Char at Current/Given Position in Pdcurses/Ncurses
Passing a C++ Complex Array to C
Confused by Squaring MACro Sqr in C
How to Compare Char Variables (C-Strings)
How to Create Temporary Object in C++
Check Xmm Register for All Zeroes
How to Convert Concatenated Strings to Wide-Char with the C Preprocessor
How to Know the Right Max Size of Vector? Max_Size()? But No
Stl Random Distributions and Portability