Знают ли стандарты С++, что неиспользуемые частные поля будут влиять на размер?

Рассмотрим следующую структуру:

class Foo {
    int a;
};

Тестирование в g++, я получаю это sizeof(Foo) == 4, но гарантируется ли это стандартом? Разрешил ли компилятор заметить, что a является неиспользуемым частным полем и удаляет его из представления класса в памяти (что приводит к меньшему размеру)?

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

Ответ 1

Стандарт С++ не определяет много о макетах памяти. Основным правилом для этого случая является пункт 4 раздела 9 Classes:

4 Завершенные объекты и субобъекты класса типа класса должны иметь ненулевой размер. [Примечание. Объекты класса могут быть назначены, переданы в качестве аргументов в функции и возвращены функциями (кроме объектов классов, для которых было ограничено копирование или перемещение, см. 12.8). Другие правдоподобные операторы, такие как сравнение равенства, могут быть определены пользователем; см. 13.5. - конечная нота]

Теперь есть еще одно ограничение: Стандартные классы макета. (нет статических элементов, нет виртуальных объектов, одинаковой видимости для всех участников) Раздел 9.2 Class members требует совместимости макетов между различными классами для классов стандартного макета. Это предотвращает исключение членов из таких классов.

Для нетривиальных классов нестандартного макета я не вижу никаких дополнительных ограничений в стандарте. Точное поведение sizeof(), reinterpret_cast(),... определяется реализацией (т.е. 5.2.10 "Функция отображения определена реализацией".).

Ответ 2

Ответ: да и нет. Компилятор не смог точно показать это поведение в стандарте, но он мог бы сделать это частично.

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

Однако компилятор не может сообщить об этом меньшему sizeof(). В стандарте довольно ясно, что объекты должны быть достаточно большими, чтобы содержать биты и байты, которые они содержат (см., Например, 3.9/4 в N3797), и сообщать о размере меньше, чем требуется для хранения int, было бы неправильно.

В N3797 5.3.2:

Оператор sizeof дает количество байтов в объекте представление его операнда

Я не вижу, чтобы "представление" могло меняться в зависимости от того, ссылается ли структура или член.

Как другой способ взглянуть на него:

struct A {
  int i;
};
struct B {
  int i;
};
A a;
a.i = 0;
assert(sizeof(A)==sizeof(B));

Я не вижу, чтобы это утверждение могло быть допущено к ошибке в реализации, соответствующей стандарту.

Ответ 3

Если вы посмотрите на шаблоны, вы заметите, что "оптимизация" таких часто заканчивается почти ничем в выходе, хотя файлы шаблонов могут быть тысячами строк...

Я думаю, что оптимизация, о которой вы говорите, почти всегда будет возникать в функции, когда объект используется в стеке, и объект не копируется или не передается другой функции, а частное поле никогда не доступно (не даже инициализированный... который можно рассматривать как ошибку!)