PODs and inheritance in C++11. Does the address of the struct == address of the first member?
c++, c++11, language-lawyer
Solution
You don't care about POD-ness, you care about standard-layout. Here's the definition, from the standard section 9 `[class]`:
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.
And the property you want is then guaranteed (section 9.2 `[class.mem]`):
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.
This is actually better than the old requirement, because the ability to `reinterpret_cast` isn't lost by adding non-trivial constructors and/or destructor.
Now let's move to your second question. The answer is not what you were hoping for.
Base *b = new Derived;
delete b;
is undefined behavior unless `Base` has a virtual destructor. See section 5.3.5 (`[expr.delete]`)
In the first alternative (delete object), if the static type of the object to be deleted is different from its dynamic type, the static type shall be a base class of the dynamic type of the object to be deleted and the static type shall have a virtual destructor or the behavior is undefined.
Your earlier snippet using `malloc` and `free` is mostly correct. This will work:
Base *b = new (malloc(sizeof(Derived))) Derived;
free(b);
because the value of pointer `b` is the same as the address returned from placement new, which is in turn the same address returned from `malloc`.
Problem
(I've edited this question to avoid distractions. There is one core question which would need to be cleared up before any other question would make sense. Apologies to anybody whose answer now seems less relevant.) Let's set up a specific example: ``` struct Base { int i; }; ``` There are no virtual method, and there is no inheritance, and is generally a very dumb and simple object. Hence it's Plain Old Data (POD) and it falls back on a predictable layout. In particular: ``` Base b; &b == reinterpret_cast<B*>&(b.i); ``` This is according to Wikipedia (which itself claims to reference the C++03 standard): A pointer to a POD-struct object, suitably converted using a reinterpret cast, points to its initial member and vice versa, implying that there is no padding at the beginning of a POD-struct.[8] Now let's consider inheritance: ``` struct Derived : public Base { }; ``` Again, there are no virtual methods, no virtual inheritance, and no multiple inheritance. Therefore this is POD also. Question: Does this fact (Derived is POD in C++11) allow us to say that: ``` Derived d; &d == reinterpret_cast<D*>&(d.i); // true on g++-4.6 ``` If this is true, then the following would be well-defined: ``` Base *b = reinterpret_cast<Base*>(malloc(sizeof(Derived))); free(b); // It will be freeing the same address, so this is OK ``` I'm not asking about `new` and `delete` here - it's easier to consider `malloc` and `free`. I'm just curious about the regulations about the layout of derived objects in simple cases like this, and where the initial non-static member of the base class is in a predictable location. Is a Derived object supposed to be equivalent to: ``` struct Derived { // no inheritance Base b; // it just contains it instead }; ``` with no padding beforehand?