Is `reinterpret_cast` actually good for anything?
Asked Answered
F

3

4

I recently learned that it is Undefined Behavior to reinterpret a POD as a different POD by reinterpret_casting its address. So I'm just wondering what a potential use-case of reinterpret_cast might be, if it can't be used for what its name suggests?

Fanciful answered 29/7, 2021 at 12:38 Comment(14)
It has some uses probably the most common is in implementing the PImpl idiom using a void *Gossett
related/dupe: https://mcmap.net/q/64043/-when-to-use-reinterpret_castAcey
Casting a POD or an array of scalars to a char array, for instance.Hind
@RichardCritten - You don't need reinterpret_cast to convert object pointers from void*Kildare
@Hind I was getting failures when casting between two PODs that both contain only std::array<double,2>.Fanciful
You can reinterpret_cast to a character type (ref or pointerHarpist
@m88 No, you mustn’t use reinterpret_cast for that. Use static_cast.Breana
@KonradRudolph Yeah my bad, I thought static_cast was for upcast only.Romeu
Not to say that it has to be designed that way, but good luck doing just about anything in the Windows API without reinterpret_casts. For example, window messages often have a pointer passed in as an integral type and you're expected to cast it back.Catherine
@463035818_is_not_a_number Regarding the request in the comments of the deleted answer, here is the defect report : open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1839r2.pdfLeontine
There is a list of use cases for reinterpret_cast here. Note that most of those use cases are not actually useful. For example, converting an object to its own type or simply allowing a back-and-forth between two types with the intermediate value being otherwise unusable (ex. can convert A to B but using B is UB, though it can be converted back to A).Leontine
I don't think this question would have been closed if the title was more objective (ex. "What is a well defined use case for reinterpret_cast?". Maybe retitling it will see it reopened.Leontine
@FrançoisAndrieux Maybe another title would be better. But even the current title is entirely fine. The question is fine as it is, there’s need not be anything opinion-based about it.Breana
Is reinterpret_cast mostly useless?Underlay
B
6

There are two situations in which I’ve used reinterpret_cast:

  1. To cast to and from char* for the purpose of serialisation or when talking to a legacy API. In this case the cast from char* to an object pointer is still strictly speaking UB (even though done very frequently). And you don’t actually need reinterpret_cast here — you could use memcpy instead, but the cast might under specific circumstances avoid a copy (but in situations where reinterpreting the bytes is valid in the first place, memcpy usually doesn’t generate any redundant copies either, the compiler is smart enough for that).

  2. To cast pointers from/to std::uintptr_t to serialise them across a legacy API or to perform some non-pointer arithmetic on them. This is definitely an odd beast and doesn’t happen frequently (even in low-level code) but consider the situation where one wants to exploit the fact that pointers on a given platform don’t use the most significant bits, and these bits can thus be used to store some bit flags. Garbage collector implementations occasionally do this. The lower bits of a pointer can sometimes also be used, if the programmer knows that the pointer will always be aligned e.g. at an 8 byte boundary (so the lowest three bits must be 0).

But to be honest I can’t remember the last concrete, legitimate situation where I’ve actually used reinterpret_cast. It’s definitely many years ago.

Breana answered 29/7, 2021 at 13:9 Comment(9)
I've always thought of reinterpret_cast as a way to say to a following developer "This is probably undefined behavior but we have to do it because it's how this API works, here be dragons" in a nice searchable package. If it was safe you'd be using static_castExhibition
@Exhibition That’s a common misunderstanding. reinterpret_cast’s purpose, at least nowadays, is definitely not to exploit UB. You really shouldn’t ever rely on UB (ignoring some standards defects). You can rely on implementation-defined behaviour, but that‘s fundamentally different. reinterpret_cast helps exploit implementation-defined behaviour, not UB. But you’re right that historically UB used to be treated in a more blasé fashion, and some platform APIs outright required UB.Breana
I guess what I'm saying is that reinterpret_cast is basically a good way to indicate something has dragons associated even if they aren't technically UB. Things like casting a pointer through void* for example. Yes you can do it with static_cast but it's a better indication to the following developer to use reinterpret_cast to indicate the danger.Exhibition
@Exhibition No, why would it be better? On the contrary, using static_cast in this situation is definitely better, because it indicates that the result of the cast is well-defined, safe and does exactly what’s expected. reinterpret_cast, if anything, give the impression “I don’t know exactly what I’m doing”. Always prefer the narrowest available cast, only drop to more permissible casts if you have to.Breana
Just to emphasise this point: you should definitely not use reinterpret_cast where static_cast works. Even ignoring other reasons, this is error-prone! Because the compiler will save you from yourself if you’re using static_cast but are accidentally trying to cast the wrong type. With reinterpret_cast the compiler gives up and won’t catch many silly mistakes that using static_cast will prevent.Breana
In the specific case of casting to and from void* I'll extremely disagree. It's not safe despite being defined. Using reinterpret_cast makes it quickly searchable in a codebase, static_cast does not. For the simple reason you mention above, that you should be using it. So unless you make your own inline fake cast mine::dangerous_cast I'd use reinterpret_cast so it's easy to find.Exhibition
@Exhibition See my last comment. Even if casting away type safety is inherently unsafe, using reinterpret_cast makes the code less safe. reinterpret_cast may be a warning sign in your personal coding style, but it’s also the cause of errors. At any rate, void* itself is sufficient warning. Relying on reinterpret_cast as a warning sign is completely redundant.Breana
@FrançoisAndrieux read up... I mentioned doing that 😉Exhibition
Maybe you haven’t used it this way, but the first-member case is worth mentioning as well.Argumentum
F
1

Conforming implementations of C and C++ are allowed to extend the semantics of C or C++ by behaving meaningfully even in cases where the Standards would not require them to do so. Implementations that do so will may be more suitable for a wider range of tasks than implementations that do not. In many cases, it is useful to have consistent syntax to specify constructs which will be processed meaningfully and consistently by implementations that are designed to be suitable for low-level programming tasks, even if implementations which are not designed to be suitable for such purposes would process them nonsensically.

Fancher answered 30/7, 2021 at 15:55 Comment(0)
J
0

One very frequent use case is when you're working with C library functions that take an opaque void * that gets forwarded to a callback function. Using reinterpret_cast on both sides of the fence, so to speak, keeps everything proper.

Jerrilyn answered 29/7, 2021 at 12:41 Comment(4)
You don’t need reinterpret_cast to cast object pointers to/from void* (you need it for objects, but that’s UB, though still done).Breana
static_cast works (and I would have said is preferable?)Harpist
@Harpist I'd actually say reinterpret_cast is preferable although you can do it with static_cast. The reasoning being that use of reinterpret_cast should always indicate danger. Casting through void* is always a point of danger IMO.Exhibition
The implicit conversion to a void* is a static_cast, and to un-do an implicit conversion you also use static_cast. It is the proper one to use for this.Riesling

© 2022 - 2024 — McMap. All rights reserved.