Размер класса в определенной иерархии

112
07 сентября 2021, 04:20

Почему объект класса A занимает 4 байта?

#include <iostream>

struct F {};
struct D: F {};
struct E: F {};
struct B: D, E {};
struct C: D, E {};
struct A: B, C {};

int main() {
    std::cout << sizeof(A{}) << '\n';
}
Answer 1

Правило "оптимизации пустых базовых классов" (empty base optimization) позволяет пустым базовым подобъектам иметь размер 0 в составе объекта-наследника. Однако в то же время два различных базовых подобъекта одного и того же типа обязаны иметь разные адреса, даже если они пусты. У вас в вашей иерархии в классе A набирается как минимум 4 различных базовых подобъекта типа F. Это уже требует размера как минимум в 4 минимальных адресуемых единицы памяти.

Если сделать

int main() 
{
  A a;
  std::cout << sizeof a << std::endl;
  std::cout << &a << std::endl;
  std::cout << (F *)(D *)(B *) &a << std::endl;
  std::cout << (F *)(E *)(B *) &a << std::endl;
  std::cout << (F *)(D *)(C *) &a << std::endl;
  std::cout << (F *)(E *)(C *) &a << std::endl;
}

то получаем (GCC, Clang)

4
0x7ffcc5ed5f5c
0x7ffcc5ed5f5c
0x7ffcc5ed5f5d
0x7ffcc5ed5f5e
0x7ffcc5ed5f5f

MSVC++, похоже, полагает, что для последнего (по порядку в памяти) подобъекта F нужен лишь уникальный адрес, но не нужно фактического байта памяти, по каковой причине размер A получается равным 3. Это нехорошо, ведь какой-то другой - внешний по отношению к A - объект может разместиться по тому же адресу, что и последнее F в A.

Проверим

struct X
{
  A a;
  char c;
};
int main() 
{
  X a; 
  std::cout << sizeof a << std::endl;
  std::cout << &a << std::endl;
  std::cout << (F *)(D *)(B *) &a.a << std::endl;
  std::cout << (F *)(E *)(B *) &a.a << std::endl;
  std::cout << (F *)(D *)(C *) &a.a << std::endl;
  std::cout << (F *)(E *)(C *) &a.a << std::endl;
  std::cout << (void *) &a.c << std::endl;
}

получаем

3
000000B30CEFFA44
000000B30CEFFA44
000000B30CEFFA45
000000B30CEFFA46
000000B30CEFFA47
000000B30CEFFA47

Если я не ошибаюсь, совпадение адресов (F *)(E *)(C *) &a.a и &a.c является нарушением требований спецификации языка, т.е. багом в MSVC++.

Answer 2

В C++ стандарте размер структуры должен иметь минимум один байт.

1.8 The C ++ object model

Unless it is a bit-field (9.6), a most derived object shall have a non-zero size and shall occupy one or more bytes of storage. Base class subobjects may have zero size. An object of trivially copyable or standard-layout type (3.9) shall occupy contiguous bytes of storage.

Структура F имеет размер один байт. D = F + 0 = 1 . B = D + E = 1 + 1 = 2 . A = B + C = 2 + 2 = 4 .

READ ALSO
Указатель объявляется в каждом проходе цикла. Правильно ли это?

Указатель объявляется в каждом проходе цикла. Правильно ли это?

Отвечаю на вопрос, связанный с переобъявлениемВ масштабе вашего кода все нормально

110
Вставить данные в поле

Вставить данные в поле

Есть html типа

126
Печать DataTable

Печать DataTable

Надо распечатать DataTable(DataGrid) в горизонтальной(альбомной) ориентацииПробовал печатать DataGrid, не влазит(много колонок)

145
Как сравнить масивы по значению

Как сравнить масивы по значению

Есть Dictionary < int[], string > example_dictionary , при записи в него новой переменной мне надо проверить, существует ли уже данный ключ, но если делать так:

148