Пусто Оптимизация элементов данных: возможно ли это?

В C ++ большинство оптимизаций происходит из правила «как если бы». То есть, пока программа ведет себя так, как если бы не была проведена оптимизация, они действительны.

Оптимизация пустой базы - одна из таких уловок: в некоторых условиях, если базовый класс пуст (не имеет никакого нестатический элемент данных), то компилятор может исключить его представление в памяти.

Похоже, что стандарт запрещает эту оптимизацию для элементов данных, то есть даже если член данных пуст, он все равно должен принимать хотя бы один байт Стоимость места: от n3225, [class]

4 - Полные объекты и подобъекты-члены типа class должны иметь ненулевой размер.

Примечание: это приводит к использованию частного наследования для разработки политики, чтобы EBO включался, когда это необходимо

Мне было интересно, можно ли, используя правило «как если бы», выполнить эту оптимизацию.


edit : следуя ряду ответов и комментариев, чтобы прояснить, что меня интересует .

Сначала позвольте мне привести пример:

struct Empty {};

struct Foo { Empty e; int i; };

У меня вопрос, почему sizeof (Foo)! = Sizeof (int) ? В частности, если вы не укажете некоторую упаковку, есть вероятность, что из-за проблем с выравниванием Foo будет вдвое больше, чем int, что кажется смехотворно завышенным.

Примечание: мой вопрос не в том, почему sizeof (Foo)! = 0 , EBO также не требует этого

Согласно C ++, это потому, что ни один подобъект не может иметь нулевой размер. Однако базе разрешено иметь нулевой размер (EBO), поэтому:

struct Bar: Empty { int i; };

скорее всего (благодаря EBO) будет подчиняться sizeof (Bar) == sizeof (int) .

Steve Jessop , похоже, придерживается мнения, что это так, чтобы никакие два подобъекта не имели одинаковых адресов. Я подумал об этом, однако в большинстве случаев это не мешает оптимизации:

Если у вас есть «неиспользуемая» память, то это тривиально:

struct UnusedPadding { Empty e; Empty f; double d; int i; };
// chances are that the layout will leave some memory after int

Но на самом деле это даже «хуже», потому что Пустое пространство никогда не записывается (лучше этого не делать, если EBO сработает ...), и поэтому вы можете разместить его в занятом месте, которое не является адресом другого объекта:

struct Virtual { virtual ~Virtual() {} Empty e; Empty f; int i; };
// most compilers will reserve some space for a virtual pointer!

Или , даже в нашем исходном случае:

struct Foo { Empty e; int i; }; // deja vu!

Можно было бы иметь (char *) foo.e == (char *) foo. i + 1 , если бы нам нужен был только другой адрес.

15
задан Matthieu M. 7 January 2011 в 10:38
поделиться