reinterpret_cast<>
with pointers to void
.
You've come to this page because you've mixed
reinterpret_cast<>
with pointers to void
,
with code similar to the following
struct T { /*…*/ } ; T * a = new T ; void * void_ptr = reinterpret_cast<void *>(a) ; T * b = reinterpret_cast<T *>(void_ptr) ;
This is the Frequently Given Answer to such admixtures.
You may think that it's legal to mix reinterpret_cast<>
with pointers-to-void
. Many people do. It's in numerous
tutorials and code snippets on the World Wide Web (such as
this one
and
this one),
and occurs as an example in books. (It was even in Bjarne Stroustrup's
The C++ Programming Language on page 342 until it was
noticed and fixed in the 3rd Edition.)
Programmers use it in code, and their C++
compilers accept it without batting an eyelid. It's passed around by word
of mouth, and it's deeply entrenched in many people's thinking.
They're all wrong. If you want to create well-formed C++ programs, that
actually adhere to the letter of the C++ Standard, then you must use
static_cast<>
for such conversions. The C++
Standard explicitly prohibits this use of
reinterpret_cast<>
.
In the opinions of a number of people, including some members of the U.K.'s C++ standards Panel, this is a defect in the C++ Standard that needs fixing. I've written a proposed revised wording for fixing this defect.
Nonetheless, as the C++ Standard stands, and as it has stood for the
past decade, reinterpret_cast<>
of pointers to
void
is not well-formed code.
The relevant portion of ISO/IEC 14882:1998 is §5.2.10 ¶1, which says:
Conversions that can be performed using
reinterpret_cast
are listed below. No other conversion can be performed explicitly usingreinterpret_cast
.
The simple fact of the matter is that none of the conversions
listed below that paragraph is a conversion either to or from pointer to
void
. It's simply not there. Since it's not a listed
conversion, it cannot, per the quite clearly expressed constraint upon
programs that that paragraph lays out, be used in a well-formed program.
Any program that mixes reinterpret_cast<>
with pointers
to void
is, in fact, ill-formed.
One can use reinterpret_cast<>
for converting between
pointers to object types. This is permitted via ¶7 of
§5.2.10. But as §3.9 ¶2 explains (and
§4.10 ¶2 reiterates), pointers to void are not pointers to
object types.
Conversion from a pointer to object type to pointer-to-void
is a standard pointer conversion, as described in §4.10 ¶2
of the Standard. Similarly, both §5.2.9 ¶6 and ¶10
permit conversion from pointer-to-void
to pointer to object
type using static_cast<>
. Thus the code snippet at
the top of this Frequently Given Answer should, to be well-formed, read:
struct T { /*…*/ } ; T * a = new T ; void * void_ptr = a ; // standard pointer conversion, no explicit cast needed T * b = static_cast<T *>(void_ptr) ; // static_cast<> can reverse a standard pointer conversion
Pretty much all C++ implementations permit this illegal use of
reinterpret_cast<>
in practice. One could view this as
an implementation conformance issue, a diagnosable rule that no
implementation actually enforces. But is far better viewed as a defect in
the C++ Standard. The implementations are right. The Standard is wrong,
and isn't standardizing existing practice.
It is far better viewed as a defect in the C++ Standard not least because
the C++ Standard actually contradicts itself on this matter. The idea
that one can reinterpret_cast<>
to and from a
pointer-to-void
, despite the Standard explicitly saying that
one cannot, is so pervasive that even the people who have worked on the
Standard in the past 10 years think that it's the case, and have
written other parts of the Standard on the basis that one can.
In particular, §3.7.4.3 ¶3 of the new version of ISO/IEC
9899, currently at Draft International Standard stage, explicitly defines
program semantics in terms of
reinterpret_cast<void *>
. So the new draft C++
Standard is in the rather unfortunate position of defining things in terms
of program constructs that it explicitly states to be prohibited.