reinterpret_cast
in C++ is considered dangerous by many people and it is hard to use it correctly without invoking UB. It also has various different usages and fail to convey the intention behind the cast well. Recent standards have added a lot of features that aims at type conversion preserving the underlying object representation, including but may not be limited to std::bit_cast
, std::span::as_bytes
and std:span::as_writable_bytes
, as well as std::start_lifetime_as
and std::start_lifetime_as_array
. This makes me wonder whether there are any reasons for reinterpret_cast
usages corresponding to these in newer code.
Maybe the question title is not entirely accurate, but I am interested in whether there are any practical use for reinterpret_cast
in newer code that corresponds to items 7 and 11 (and maybe also 10) in the standard draft. I am interested in a detailed answer stating how each usage is or is not superceded and what is the recommended way in place of them in the case they are superceded. I am aware that there are many other uses for reinterpret_cast
that are not superseded by new features in the language.
- An object pointer can be explicitly converted to an object pointer of a different type.57 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)).
- ...
- ...
- A prvalue of type “pointer to member of X of type T1” can be explicitly converted to a prvalue of a different type “pointer to member of Y of type T2” if T1 and T2 are both function types or both object types.58 The null member pointer value ([conv.mem]) is converted to the null member pointer value of the destination type. The result of this conversion is unspecified, except in the following cases:
- Converting a prvalue of type “pointer to member function” to a different pointer-to-member-function type and back to its original type yields the original pointer-to-member value.
- Converting a prvalue of type “pointer to data member of X of type T1” to the type “pointer to data member of Y of type T2” (where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer-to-member value.
- A glvalue of type T1, designating an object x, 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. The result is that of *reinterpret_cast<T2 *>(p) where p is a pointer to x of type “pointer to T1”. No temporary is created, no copy is made, and no constructors ([class.ctor]) or conversion functions ([class.conv]) are called.59
57 The types can have different cv-qualifiers, subject to the overall restriction that a reinterpret_cast cannot cast away constness.
58 T1 and T2 can have different cv-qualifiers, subject to the overall restriction that a reinterpret_cast cannot cast away constness.
59 This is sometimes referred to as a type pun when the result refers to the same object as the source glvalue.
std::bit_cast
and std::start_lifetime_as
don't replace reinterpret_cast
, they are new capabilities that reinterpret_cast
never had. std::span::as_bytes
is a convenience function, which is as much to help with std::dynamic_extent
as it is to wrap the cast.
So the useful usages of reinterpret_cast
haven't changed. What has changed is there are defined behaviour replacements for constructs where people were using reinterpret_cast
with undefined behaviour.