Is casting the first field of an object to the object's type actually safe?
c++, casting, undefined-behavior
Solution
A pointer to a standard-layout struct object, suitably converted using a reinterpret_cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa. [ Note: There might therefore be unnamed padding within a standard-layout struct object, but not at its beginning, as necessary to achieve appropriate alignment. — end note ]
(C++11, §9.2, ¶21)
So, this is safe as long as a class is "standard-layout", i.e.:
A standard-layout class is a class that:
- has no non-static data members of type non-standard-layout class (or array of such types) or reference,
- has no virtual functions (10.3) and no virtual base classes (10.1),
- has the same access control (Clause 11) for all non-static data members,
- has no non-standard-layout base classes,
- either has no non-static data members in the most derived class and at most one base class with non-static data members, or has no base classes with non-static data members, and
- has no base classes of the same type as the first non-static data member.
(C++11, §9, ¶7)
All the requirements about the virtual stuff are because of the vptr: as said above, many compilers put it as a first hidden member, but they are allowed to put it anywhere or, if they are able, to omit it at all or implement virtual dispatch in other ways, so virtual in general alters the layout of the class in an unspecified way.
The "same access control clause" is because
The order of allocation of non-static data members with different access control is unspecified.
(C++11, §9.2, ¶15)
I suppose that this may be to allow compilers to reorder/group the members of a class by access-control (i.e. inside the compiler the IR of a class may contain a list for the members under each access-control specifier, which does not allow to keep the original ordering - all the interleaved public/private/protected sections would be grouped and e.g. the private members may be put in front of the class by default).
The no non-standard-layout members/base classes "recursive" clauses are to ensure that the class is standard-layout as a whole (base classes and members are a part of it).
Additional details on why the rest of this stuff can affect the layout of the class may be found in §9.2.
Notice that this is a weaker condition than the class being POD (as I incorrectly said in the comment above), since a class is POD if it is both standard layout and trivial (§9 ¶10)
Problem
At first glance, this looks like undefined behavior... ``` #include <iostream> struct SomeBaseClass { // ... }; struct MyFakerClass { SomeBaseClass base; void foo() { std::cout << "hello" << std::endl; } }; int main() { MyFakerClass c; MyFakerClass *p = static_cast<MyFakerClass *>(static_cast<void *>(&c.base)); p->foo(); } ``` ... but if the first field of an object is guaranteed to have the same address as the object, then this must be safe, right? Or is there some other rule that intervenes?