Re: Replacing old C-style casts with static|reinterpret_cast?



On Wed, 10 May 2017 17:22:51 +0100
Daniel Boles <dboles src gmail com> wrote:
Murray mentioned on a Bugzilla that replacing these with
static_cast<> is always good.

Is the same true for cases where we need reinterpret_cast<> ? That is
semi frequent because GTK+ types are opaque even to us, so converting
pointers cannot use static_cast<> as the latter cannot verify that
e.g. both types have the same 1st member.

The raw C cast would ultimately boil down to a reinterpret_cast
anyway, so my POV is that we should explicitly write the latter, as
it signals that we know what we're doing - rather than the raw cast,
which only really says 'try everything you can think of, and pick
anything that barely works'!

You can use reinterpret_cast when casting between C types which employ
"C style" inheritance (that is, where the "parent" is a struct which is
the first member of the "child" struct).  This is because C structs are
of necessity standard layout types in C++ speak.  More to the point,
because such inheritance is not inheritance in the C++ sense (they are
unrelated types from the C++ inheritance point of view) casting can
only be done using a C cast or a reinterpret_cast, which is guaranteed
to work by §9.2/20 of the C++ standard.

If that was what your post was about, then I think you are fine.  But
if you were looking at casting more broadly, you cannot assume that any
other valid C cast can be replaced by a reinterpret_cast.  This is
because C casts degrade according to the order set out in §5.4/4 of the
C++ standard, and they will only be implemented as a reinterpret_cast
where a static_cast is not available (and of course a reinterpret_cast
cannot perform a const cast).

This is important because a static cast (and so a C cast) can
be used to navigate an inheritance graph of types which do not have
standard layout, and will adjust pointer addresses on casting
automatically.  This means that, amongst other things, a static_cast can
cast between, say, a virtual derived class and its non-virtual base
(objects of which will generally have different addresses because of
the vtable of the derived class), and also between derived types and
base types where multiple inheritance is employed.  reinterpret_cast on
the other hand will never adjust pointer addresses and will give
undefined behaviour in such cases.

As it happens, one cast can only be made using a C style cast.  A C
style cast will allow you to cast from a derived type to its private
base (that is, where private inheritance is used), even if both are not
standard layout types, and make the correct pointer adjustment.
static_cast will refuse the cast, and reinterpret_cast will allow it
but give undefined behaviour where pointer adjustments would be
required for the cast to succeed.

Except when navigating "C style" or "C++ style" inheritance graphs,
reinterpret_cast and C casts both give rise to strict aliasing issues
when using them for type punning (§3.10/10 of the standard), but that
is a separate matter.

You probably know all this but that wasn't clear from your question.

Chris


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]