Ссылки на одни и те же базовые классы должны иметь отдельные смещения в памяти

Я обнаружил некоторые несоответствия между компиляторами с этой программой,

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 имеют разные ссылки? Ищете интуицию, почему это так?

Кто-то сказал, что это может быть условие, требуемое стандартом, и нам было любопытно, в чем причина?

Спасибо

8

Решение

Стандарт определенно предписывает, что адрес каждого объекта одного типа отличается. Соответствующий пункт 5.10 [expr.eq] пункт 1:

Два указателя одного и того же типа сравниваются равными, если и только если они оба равны нулю, оба указывают на одну и ту же функцию или оба представляют один и тот же адрес (3.9.2).

Это необходимо, чтобы различать два объекта. Объекты имеют как ценность, так и идентичность. Для подобъекта базового класса разумно иметь тот же адрес, что и вмещающий класс. Для члена класса вы можете различить идентичность двух объектов по их типу, т. Е. Для них нормально иметь один и тот же адрес. Для двух объектов одного типа вам все равно понадобится что-то, чтобы различать объекты по их идентичности.

3

Другие решения

Да, это упоминается в 10p8:

Субобъект базового класса может иметь нулевой размер (раздел 9); тем не мение, два
подобъекты, имеющие одинаковый тип класса и принадлежащие одному и тому же
самый производный объект не должен размещаться по одному и тому же адресу (5.10)
.

В C у вас есть два As, один наследуется, а другой является частью B, Microsoft настойчиво и ошибочно применяет пустую оптимизацию базового класса здесь, когда этого не следует делать. Я считаю, что это известная ошибка, но действительно трудно найти отчет об ошибке в Microsoft Connect.

3

В C ++ объект однозначно определяется парой данных: его адресом и его типом.

Как вы правильно заметили, оба C а также D содержат два отдельных подобъекта A для которого это должно быть правдой. Однако в зависимости от того, как вы выложите B в памяти, вы можете увидеть, как было бы невозможно поставить оба A-подобъекты по разным адресам в пределах 8-байтовой структуры.

Почему бы вам не распечатать фактические числовые адреса подобъектов?

1
По вопросам рекламы [email protected]