8

There's a set of questions regarding cross-casts (cast from T1* to unrelated T2*), for example this and this. The answer usually goes like this: reinterpret_cast is implementation defined and conversion to void* followed by static_cast is well-defined. Yet I haven't see any real examples of what can go wrong when reinterpret_cast is used.

What are real-life examples where casting through void* works and reinterpret_cast doesn't?

Community
  • 1
  • 1
sharptooth
  • 167,383
  • 100
  • 513
  • 979
  • 3
    I was under the impression that `reinterpret_cast` to `char*` actually *was* well-defined (but unspecified, yes). And that, furthermore, cast to `void*`, followed to cast to an undefined type, is undefined. `void*` should only be used to erase and restore *the same type*. (See also Johannes’ comment to Pavel’s answer which states about the same, just more rigorously.) – Konrad Rudolph Jul 06 '11 at 10:30
  • @sharptooth: "What are real-life examples where casting through void* works and reinterpret_cast doesn't?" I don't think that there are such examples. But why would you want to create implementation-specific solution (even if every implementation of your interest supported) if you can create solution with standard-specified behavior (and thus guaranteed to be portable for every conforming implementation ever existed)? – Serge Dundich Jul 06 '11 at 12:17
  • 1
    "_The answer usually goes like this: reinterpret_cast is implementation defined and conversion to void* followed by static_cast is well-defined._" then the usual answer is wrong. – curiousguy Dec 13 '11 at 14:04
  • @curiousguy: The Right Answer is welcome. – sharptooth Dec 13 '11 at 14:13
  • @sharptooth [Here it is.](http://stackoverflow.com/questions/1863069/casting-via-void-instead-of-using-reinterpret-cast/8486111#8486111) – curiousguy Dec 13 '11 at 14:17
  • @curiousguy: It doesn't go beyond "it works", that's not what I was asking for. – sharptooth Dec 13 '11 at 14:31
  • @sharptooth I guess I don't understand what you are asking for. – curiousguy Dec 13 '11 at 14:34
  • @curiousguy: Well, careful reading into the Standard reveals that there's some room for unwanted behavior when using `reinterpret_cast` and I wanted to know of real world examples if any. You just say "it will work" without even trying to list the systems on which it will work. What if it happens to not work on the embedded C++ compiler used in the vacuum cleaner I buy tomorrow? – sharptooth Dec 13 '11 at 14:40
  • @sharptooth "_there's some room for unwanted behavior when using `reinterpret_cast`_" As I have previously stated, this answer is wrong. The standard fails to define either form, but there is no doubt that the intent is that both are well defined. "_You just say "it will work" without even trying to list the systems on which it will work._" "It works" is all. It just does. Everywhere. – curiousguy Dec 13 '11 at 14:44
  • Really, you are making up a problem where there is none. – curiousguy Dec 13 '11 at 15:00

2 Answers2

1

real-life examples where casting through void* works and reinterpret_cast doesn't

If I interpret this sentence as, casting through void* works to help me avoid undefined behavior and reinterpret_cast doesn't then following is an example.

reinterpret_cast<TYPE*&> (pointer reference) may break strict aliasing rule (it happens for g++ at least) and leads you to an undefined behavior. Demo.

However, static_cast<void*&> will result in compiler error and save you from such undefined behavior. Demo.

I have seen such use in a smart pointer:

template<class TYPE>
struct SmartPointer
{
  void *p;
  TYPE& operator ++ ()
  {
    (reinterpret_cast<TYPE*&>(p))++;  // breaking strict aliasing rule
    return *this;
  }
}
iammilind
  • 68,093
  • 33
  • 169
  • 336
  • @sharptooth, I have put a real life code in the answer. See if it helps. – iammilind Jul 06 '11 at 10:46
  • "`reinterpret_cast`" Who suggested that? – curiousguy Dec 13 '11 at 14:06
  • @curiousguy, how does it matter ? This code snippet is showing the `reinterpret_cast<>` in bad light (which breaks strict aliasing rules). – iammilind Dec 13 '11 at 14:16
  • @iammilind I don't understand what you are getting at. This code fragment show a use of `reinterpret_cast` that is not well defined, and that is not what the OP wanted to do. – curiousguy Dec 13 '11 at 15:02
  • @curiousguy, I don't know if you have downvoted, but the question is `... where reinterpret_cast doesn't work ...`. The example I have mentioned answers the same. `reinterpret_cast` doesn't generate a compiler error and silently leads to undefined behavior, which essentially means it doesn't work. – iammilind Dec 15 '11 at 03:46
  • Yes, `reinterpret_cast` doesn't work. But that is not the question! The question is: when will two `static_cast` in a row convert from `T*` to `U*` as I want, but one `reinterpret_cast` will not? And the answer is: never, you are making up an issue that does not exist based on previous incorrect answers given on SO. – curiousguy Dec 15 '11 at 04:27
  • `reinterpret_cast` here is inappropriate use of `reinterpret_cast` (and it is rarely appropriate). "_reinterpret_cast doesn't generate a compiler error and silently leads to undefined behavior,_" That's typically what cast do when they are misused, they give you UB. – curiousguy Dec 15 '11 at 04:30
0

casting from T1* to unrelated T2* with reinterpret_cast is not less defined than with static_cast. Actually, when both T1 and T2 are standard layout types it works the same (see 5.2.10/7):

When a prvalue v of type “pointer to T1” is converted to the type “pointer to cv T2”, the result is static_cast<cv T2*>(static_cast<cv void*>(v))

For non-standard layout types the result of conversion is unspecified, but it's unspecified for static_cast as well.

I guess, you can get a difference only when casting non-pointer types in artificial cases like this:


struct Foo
{
};

struct Bar
{
    operator void*()
    {
        return 0;
    }
};

int main ()
{
  Bar b;
  Foo * p1 = static_cast<Foo*>(static_cast<void *>(b)); // ok, Bar::operator void* -> static_cast
  Foo * p2 = reinterpret_cast<Foo*>(b); // error, no conversion from Bar to Foo*.
}

Konstantin Oznobihin
  • 5,234
  • 24
  • 31
  • 1
    It's possible that sharptooth is talking about the current standard, C++03, not the draft you quote from. Although actually I think he's probably talking about whether it goes wrong in practice, so both standards are kind of irrelevant in the face of what implementations actually do - C++03 is irrelevant because all known implementations have more in common between their `reinterpret_cast` implementations than is actually guaranteed, and the FDIS because nobody promises to implement it yet anyway. – Steve Jessop Jul 06 '11 at 11:53