Я обнаружил некоторые несоответствия между компиляторами с этой программой,
struct A {
};
struct B : public A {
float m;
};
struct C : public A {
B b;
float n;
};
struct D : public A {
float n;
B b;
};
static_assert(sizeof(A) == 1, "");
static_assert(sizeof(B) == 4, "");
static_assert(sizeof(C) == 8, ""); // most compilers say this is 12
static_assert(sizeof(D) == 8, "");
Большинство компиляторов утверждают на sizeof (C) == 8, говоря, что sizeof (C) на самом деле равен 12. Единственный найденный мной компилятор, который не говорит и говорит, что это 8, — это Microsoft Visual Studio 2010.
Причина, по которой мне сказал кто-то умнее меня, состоит в том, что есть две отдельные ссылки на А внутри В, которые должны сохранять отдельные смещения, отличные друг от друга. Во-первых, A, полученный из C, имеет смещение 0, и второй A внутри элемента b не может быть с тем же смещением, что и первый A с 0, поэтому вставляется 4 байта заполнения.
Поскольку большинство компиляторов реализовали такое поведение, мне было интересно, в каком случае вам нужно убедиться, что оба A имеют разные ссылки? Ищете интуицию, почему это так?
Кто-то сказал, что это может быть условие, требуемое стандартом, и нам было любопытно, в чем причина?
Спасибо
Стандарт определенно предписывает, что адрес каждого объекта одного типа отличается. Соответствующий пункт 5.10 [expr.eq] пункт 1:
Два указателя одного и того же типа сравниваются равными, если и только если они оба равны нулю, оба указывают на одну и ту же функцию или оба представляют один и тот же адрес (3.9.2).
Это необходимо, чтобы различать два объекта. Объекты имеют как ценность, так и идентичность. Для подобъекта базового класса разумно иметь тот же адрес, что и вмещающий класс. Для члена класса вы можете различить идентичность двух объектов по их типу, т. Е. Для них нормально иметь один и тот же адрес. Для двух объектов одного типа вам все равно понадобится что-то, чтобы различать объекты по их идентичности.
Да, это упоминается в 10p8:
Субобъект базового класса может иметь нулевой размер (раздел 9); тем не мение, два
подобъекты, имеющие одинаковый тип класса и принадлежащие одному и тому же
самый производный объект не должен размещаться по одному и тому же адресу (5.10).
В C
у вас есть два A
s, один наследуется, а другой является частью B
, Microsoft настойчиво и ошибочно применяет пустую оптимизацию базового класса здесь, когда этого не следует делать. Я считаю, что это известная ошибка, но действительно трудно найти отчет об ошибке в Microsoft Connect.
В C ++ объект однозначно определяется парой данных: его адресом и его типом.
Как вы правильно заметили, оба C
а также D
содержат два отдельных подобъекта A
для которого это должно быть правдой. Однако в зависимости от того, как вы выложите B
в памяти, вы можете увидеть, как было бы невозможно поставить оба A
-подобъекты по разным адресам в пределах 8-байтовой структуры.
Почему бы вам не распечатать фактические числовые адреса подобъектов?