3

Where in the C++ spec is this allowed? It's cool. I want to know how this is spec'd. I didn't realize the spec allowed having a pointer to a undefined type.

class T;

int main(int argc, char* argv[])
{
   int x;
   T* p = reinterpret_cast<T*>(&x);
   return 0;
}
Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
Mike
  • 1,760
  • 2
  • 18
  • 33
  • 2
    Um, how is that allowed? Because I'm pretty sure that `reinterpret_cast` is either implementation defined behavior or *undefined behavior*. Either way, it's not defined by the spec, so I'm not sure if it could be considered "allowed". Or are you talking about just the forward declaration? – Nicol Bolas Feb 10 '12 at 20:14
  • 6
    And why would this be cool? – Bart Feb 10 '12 at 20:15
  • @Bart Because you can do nasty things, maybe? – tibur Feb 10 '12 at 20:18
  • Here's an example of why I think it is cool. http://arduino.cc/forum/index.php/topic,91314.msg685761.html#msg685761 – Mike Feb 10 '12 at 20:24
  • @Rob, I didn't realize the spec allowed having a pointer to a undefined type. – Mike Feb 10 '12 at 20:40

4 Answers4

4

The only thing you're allowed to do after casting a pointer to an unrelated type (other than char*), is cast back to the original pointer type.

@cli_hlt beat me to providing the section.

Here's the rule itself:

An object pointer can be explicitly converted to an object pointer of a different type. 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)) if both T1 and T2 are standard-layout types (3.9) and the alignment requirements of T2 are no stricter than those of T1, or if either type is void. Converting a prvalue of type "pointer to T1" to the type "pointer to T2" (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer value. The result of any other such pointer conversion is unspecified.

The strict aliasing rule prohibits access to an object through an unrelated type. See https://stackoverflow.com/a/7005988/103167

Another rule somewhat related to your question is found in section 5.4:

The operand of a cast using the cast notation can be a prvalue of type "pointer to incomplete class type". The destination type of a cast using the cast notation can be "pointer to incomplete class type" If both the operand and destination types are class types and one or both are incomplete, it is unspecified whether the static_cast or the reinterpret_cast interpretation is used, even if there is an inheritance relationship between the two classes.

Community
  • 1
  • 1
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
4

What you're doing may be legal, but that depends on the real definition of class T, so we can't know for sure based on the code you've shown.

Starting with C++11 §3.9.2/3:

Pointers to incomplete types are allowed although there are restrictions on what can be done with them.

Those restrictions are listed in §3.2/4:

A class type T must be complete if:

  • an object of type T is defined, or
  • a non-static class data member of type T is declared, or
  • T is used as the object type or array element type in a new-expression, or
  • an lvalue-to-rvalue conversion is applied to a glvalue referring to an object of type T, or
  • an expression is converted (either implicitly or explicitly) to type T, or
  • an expression that is not a null pointer constant, and has type other than void*, is converted to the type pointer to T or reference to T using an implicit conversion, a dynamic_cast or a static_cast, or
  • a class member access operator is applied to an expression of type T, or
  • the typeid operator or the sizeof operator is applied to an operand of type T, or
  • a function with a return type or argument type of type T is defined or called, or
  • a class with a base class of type T is defined, or
  • an lvalue of type T is assigned to, or
  • the type T is the subject of an alignof expression, or
  • an exception-declaration has type T, reference to T, or pointer to T.

The 6th bullet appears pertinent here, as we can see in §5.2.10/7 that a reinterpret_cast between pointer types is defined in terms of static_cast:

An object pointer can be explicitly converted to an object pointer of a different type. 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)) if both T1 and T2 are standard-layout types and the alignment requirements of T2 are no stricter than those of T1, or if either type is void. Converting a prvalue of type “pointer to T1” to the type “pointer to T2” (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer value. The result of any other such pointer conversion is unspecified.

But because reinterpret_cast static_casts to void* first, then to the real resulting pointer type, that 6th bullet doesn't apply.

So, so far you're still in legal territory, despite T being an incomplete type. However, if it turns out that T is not a standard-layout type or has stricter alignment requirements than int, then the last sentence in §5.2.10/7 holds true and you're invoking UB.

ildjarn
  • 62,044
  • 9
  • 127
  • 211
2

Section 5.2.10 (7) for your case (as of ISO/IEC14882:1998(E), as well as in the 2011 FDIS).

cli_hlt
  • 7,072
  • 2
  • 26
  • 22
0

I'm not sure what you perceive as being allowed. There is a guarantee that you can reinterpret_cast from one pointer type to a sufficiently big other pointer type and back to the original type again and will be the original pointer. The specification for this is in 5.2.10 [expr.reinterpret.cast]. That is, the following is guaranteed to work:

T* ptr = ...;
S* sptr = reinterpret_cast<S*>(ptr);
T* tptr = reinterpret_cast<T*>(sptr);
assert(ptr == tptr);

We had an out of session discussion earlier this week on this topic: if the Death Station 9000 implementation (which would be a conforming implementation of C++ but also tries to break user code wherever it is allowed to do so) XORs the bit pattern of the pointer with a bit pattern randomly chosen at the beginning of the program execution, would this be a permissible implementation if the types involved in the reinterpret_cast<T>(x) are not involving char. The consensus was that this would be OK.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • I now realize my question is not that clear. I didn't realize the spec allowed having a pointer to a undefined type. – Mike Feb 10 '12 at 20:34
  • I also just realized that my `reinterpret_cast<>()`s used the wrong type! I'll fix this in a second (sorry for any confusion I might have caused): `S` and `T` are meant to be two layout compatibly types and they were meant to be used in the casts. – Dietmar Kühl Feb 10 '12 at 20:42