size
и align
- это размер и ориентация класса при использовании в качестве полного типа. То есть, если вы создаете объекты, полный тип которых является типом (например, определение переменных этого типа или использование этого типа с помощью new
).
Размер - это просто количество байтов, которое оно занимает. Таким образом, size=16
означает, что при использовании в качестве полного типа он всегда занимает 16 байтов.
Выравнивание говорит вам, где объект может быть помещен: align=8
означает, что адрес объекта должен быть целым числом, кратным 8.
base size
и base align
дают размер и ориентацию в случае класс используется в качестве базовый класс. Причина, по которой они различны, заключается в том, что стандарт C++ позволяет объектам использовать меньшее дополнение при использовании в качестве базового класса.
Итак, давайте посмотрим конкретно на ваш пример (я предполагаю, что у вас на самом деле есть int
до double
в первом случае). Я также опускаю public
и private
, потому что здесь они ничего не меняют (если у вас есть как публичные, так и частные элементы данных, они могут в принципе что-то изменить, но я не знаю, использует ли какой-либо компилятор этот). Я также предполагаю размер и выравнивание int
и double
(фактически значения, которые я предполагаю, являются довольно распространенным выбором и объясняют полученные вами значения).
Таким образом, в первом случае (я предполагаю) у вас есть
class A
{
int m_number;
double m_nothing;
};
Теперь int
имеет размер и выравнивание 4
и двуспальный размер и выравнивание 8
.
Итак, давайте сделаем работу компилятора и построим наш класс.
Во-первых, у нас есть m_number
, который занимает 4 байта. Мы должны поставить член в заданном порядке, так m_number
идет в начале A
:
iiii
До сих пор мы имеем размер 4 (четыре байта для междунар) и выравнивание 4 (потому что ИНТ имеет выравнивание 4). Но теперь мы должны добавить двойной (размер и выравнивание 8).Поскольку непосредственно после int мы находимся на (относительном) адресе 4, мы неправильно выровнены для двойника, поэтому нам нужно добавить 4 padding байт (что я буду отмечать *
), чтобы получить кратное 8 Таким образом, мы получаем для нашего класса:
iiii****dddddddd
Теперь, если класс используется в качестве базового класса, мы закончили. Таким образом, мы используем base size=16
и base align=8
(для правильного выравнивания с двойным выравниванием нам нужно выравнивание 8).
Для всего объекта есть еще одно соображение: Стандарт требует, чтобы в массивах объекты следовали друг за другом без промежутка между ними. То есть, первый байт после того, как объект должен быть правильно выровнен для следующего объекта. В конечном итоге это означает, что размер полного объекта должен быть кратным его выравниванию.
Теперь макет объекта, который мы нашли, уже выполняет это требование. Поэтому мы можем использовать его без изменений и для всего объекта. Поэтому мы получаем size=16
и align=8
для всего объекта.
Теперь рассмотрим случай, когда обращенную порядок:
class A
{
double m_nothing;
int m_number;
};
Теперь мы должны начать с double
:
dddddddd
Далее, мы должны добавить int
. Как оказалось, на следующий свободное место уже правильно выровнены для int
, поэтому мы можем просто добавить его:
ddddddddiiii
Теперь для использования в качестве базового объекта, мы готовы. Как вы можете видеть, нам нужны только 12 байт, поэтому base size=12
. Конечно, для правильного выравнивания double
объект снова должен начинаться с адреса, который кратен 8. Поэтому мы имеем base align=8
.
Однако для судебного права, как полного объекта, мы теперь находим, что следующий адрес будет находиться в положении 12, которое равно не правильно выровнено для члена double
. Поэтому мы должны добавить байты заполнения, пока мы не достигнем правильно выровненный адрес снова:
ddddddddiiii****
Как вы можете видеть, теперь нам нужно 16 байт, таким образом size=16
. У нас все еще есть align=8
из-за двойного.
Обратите внимание, что требование выравнивания может существенно повлиять на размер класса. Рассмотрим, например, следующие два типа:
struct S1
{
char c1;
double d1;
char c2;
double d2;
char c3;
};
struct S2
{
double d1;
double d2;
char c1;
char c2;
char c3;
};
В то время как оба содержат одни и те же элементы, S1
будет с размерами и выравнивания выше, имеют в общей сложности (не базовый) размер 40, в то время как общий размер S2
будет всего 24.Действительно, объекты типа S1
будет, как полный объект, выглядеть
c*******ddddddddc*******ddddddddc*******
в то время как тип S2
будет выглядеть
ddddddddddddddddccc*****
Таким образом, нижняя линия является то, что члены с самым высоким требованием выравнивания должны всегда на первом месте.
Также обратите внимание, что sizeof
возвращает размер полных объектов, то есть, что дамп иерархии классов вызывает size
.
Я думаю, вы забыли немного изменить класс. – chris
О, извините! Во втором примере я заменил две переменные-члены. – user19840919