Всегда ли заполнение между членами класса одного и того же типа одинаково?

Следующий класс содержит несколько членов того же типа:

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

Все члены объявляются без промежуточного спецификатора доступа и, таким образом, распределяются таким образом, чтобы более поздние члены имели более высокие адреса (ISO/IEC 14882: 9.2.12). В том же абзаце сказано:

Требования выравнивания реализации могут привести к тому, что два соседних элемента не будут выделены сразу друг за другом; так же как и требования к пространству для управления виртуальными функциями (10.3) и виртуальными базовыми классами (10.1).

Теперь предположим, что MyClass не имеет виртуальных функций и виртуальных базовых классов. Всегда ли верно следующее?

//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

Или компилятору разрешено использовать произвольно больше отступов, чем требуется (по каким-то причинам...)? Например: если sizeof(T)==4 и alignof(T)==8, компилятор будет использовать 4 байта заполнения между членами. Можно ли использовать 12 байтов заполнения только между m2 и m3?

Что происходит, когда MyClass имеет виртуальные функции или виртуальные базовые классы? Действительно ли компилятору разрешено вставлять информацию, относящуюся к MyClass (например, vtable-ptr), между произвольными элементами данных? Или предложение из приведенного выше стандарта больше связано с виртуальными функциями и виртуальными базовыми классами T? Потому что, если допустимо хранить информацию, относящуюся к T, вне T, это также может иметь следующее значение:

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
    //...
};

Что опять же может дать регулярную закономерность.


person user287715    schedule 29.06.2010    source источник


Ответы (1)


Нет. Нет правила, предписывающего это, поэтому компиляторы могут вставлять отступы где угодно. «Требования к выравниванию могут…» — это всего лишь пример, а не ограничение возможных причин.

Другое дело, если бы у вас был T m[5] член, и в этом случае &(this->m[1]) - &(this->m[0]) == 1.

По той же причине: «Действительно ли компилятору разрешено вставлять информацию, относящуюся к MyClass (например, vtable-ptr), между произвольными элементами данных?» должен быть дан положительный ответ, потому что нет правила, запрещающего это. Он не мог вставить его в середину подобъекта (будь то T или T[5]), но между подобъектами все в порядке.

person MSalters    schedule 29.06.2010
comment
Но каково намерение, стоящее за предложением Нестатические элементы данных (не объединенного) класса, объявленного без промежуточного спецификатора доступа, выделяются так, чтобы более поздние члены имели более высокие адреса в объекте класса? Какой смысл в том, что отступы настолько произвольны? - person user287715; 29.06.2010
comment
Это предложение просто означает, что компилятор не может изменить порядок членов, поэтому более поздние члены не могут появиться в памяти первыми. Точнее: он ограничивает относительные смещения последующих членов строго положительными, но в остальном неопределенными значениями. - person MSalters; 29.06.2010
comment
Да, но тогда для чего? Взгляните на bytes.com/topic/c/answers/610289- структура-макет-вопрос. Это C, а не C++, но это та же тема. - person user287715; 29.06.2010
comment
В C вы можете преобразовать struct { int; float; double; }* в struct {int, float* }. Это было бы проблематично, если бы двойник был перемещен перед поплавком. - person MSalters; 30.06.2010
comment
Он также должен работать в C++ с POD-структурами. Но тогда мне все же интересно, почему ограничение из 9.2/12 сделано для всех классов, а не только для POD-структур... - person user287715; 01.07.2010