views:

48

answers:

1

The following class contains some members of the same type:

template <typename T>
class MyClass
{
    T m0;
    T m1;
    T m2;
    T m3;
    T m4;
    //...
};

The members are all declared without an intervening access-specifier and thus are allocated that later members have higher addresses (ISO/IEC 14882: 9.2.12). The same paragraph says:

Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other; so might requirements for space for managing virtual functions (10.3) and virtual base classes (10.1).

Now let's assume that MyClass has no virtual functions and no virtual base classes. Is the following always true?

//inside a member function of MyClass

(char*)&m0 == (char*)&m0 + ((char*)&m1-(char*)&m0) * 0
(char*)&m1 == (char*)&m0 + ((char*)&m1-(char*)&m0) * 1
(char*)&m2 == (char*)&m0 + ((char*)&m1-(char*)&m0) * 2
(char*)&m3 == (char*)&m0 + ((char*)&m1-(char*)&m0) * 3
(char*)&m4 == (char*)&m0 + ((char*)&m1-(char*)&m0) * 4

Or is the compiler allowed to use arbitrary more padding than required (for whatever reasons...) ? For example: If sizeof(T)==4 and alignof(T)==8 the compiler will use 4 padding-bytes between the members. Would it be valid to use 12 padding-bytes only between m2 and m3?

What is the case when MyClass has virtual functions or virtual base classes? Is the compiler really allowed to insert information related to MyClass (like a vtable-ptr) between arbitrary data members? Or is the sentence from the standard above more related to virtual functions and virtual base classes of T? Because if it's valid to store information related to T outside T it could also have the following meaning:

template <typename T>
class MyClass
{
    T m0;
    //space to manage virtual functions and base classes of m0
    //padding
    T m1;
    //space to manage virtual functions and base classes of m1
    //padding
    T m2;
    //space to manage virtual functions and base classes of m2
    //...
};

What again might give a regular pattern.

+2  A: 

No. There's no rule mandating it, therefore compilers may insert padding anywhere. "Alignment requirements might ..." is merely an example, and not a restriction on possible causes.

It would be a different matter if you had a T m[5] member, in which case &(this->m[1]) - &(this->m[0]) == 1.

For the same reason, "Is the compiler really allowed to insert information related to MyClass (like a vtable-ptr) between arbitrary data members?" must be answered positively, because there is no rule that forbids it. It couldn't insert it in the middle of a subobject (whether that's a T or a T[5]), but between subobjects is fine.

MSalters
But what is the intention behind the sentence "Nonstatic data members of a (non-union) class declared without an intervening access-specifier are allocated so that later members have higher addresses within a class object."? Where does it make sense if padding is so much arbitrary?
That sentence merely means that the compiler cannot change the order of members so later members cannot appear in memory first. More precisely: It restricts relative offsets of subsequent members to strictly positive, but otherwise unspecified values.
MSalters
Yes, but then for what? Have a look at http://bytes.com/topic/c/answers/610289-structure-layout-question. It's C, not C++, but it's the same topic.
In C, you can cast a `struct { int; float; double; }*` to a `struct {int, float* }`. This would be problematic if the double would be moved before the float.
MSalters
It should also work in C++ with POD-structs. But then I'm still wondering why the restriction from 9.2/12 is made for all classes and not only for POD-structs...