Я недавно спросил об этом на comp.std.c ++ и не получил ответа.
Я просто процитирую там мой пост с небольшой модификацией.
Является ли последнее требование стандартов классов 9/6 необходимым или полезным?
Предоставлено сноска:
Это гарантирует, что два подобъекта, которые
имеют тот же тип класса и
принадлежат к тому же самому производному объекту
не размещены по одному адресу
(5,10).
Взятые в одиночку, сноска неверна. Два пустых базовых класса с
общий базовый класс может производить два экземпляра базового класса на
тот же адрес.
struct A {};
struct B : A {};
struct C : A {};
struct D : B, C {};
D d;
static_cast<A*>(static_cast<B*>(&d))
== static_cast<A*>(static_cast<C*>(&d)); // allowed per 1.8/5
Взятые в контексте 5.10, подобъекты упоминаются только в
требования сравнения указателей к членам. Базовыми подобъектами являются
не имеет значения. Более того, это не делает
смысл придавать особый статус сравнению (скалярного) указателя на
подобъект члена и указатель на базовый подобъект выше объекта
сравнение между указателями на базовые подобъекты.
В C ++ 03 такого ограничения не было. Даже если есть ABI, который требует от каждого члена
размещены по другому адресу из любой базы того же типа, но
уже позволяет пустую оптимизацию базового класса по приведенному выше коду, я
думаю, что ABI глючит, и стандарт не должен это фиксировать.
Язык восходит к N2172
что предполагает, что множественное наследование может вызвать проблемы и необходимость
быть запрещенным в классах стандартной компоновки для обеспечения совместимости ABI ;
однако в конечном итоге это было разрешено, и в этом свете требование
не имеет смысла.
Для справки: 1,8 / 5-6:
5 Если это не битовое поле (9.6),
наиболее производный объект должен иметь
ненулевой размер и должен занимать один или
больше байтов памяти. Базовый класс
подобъекты могут иметь нулевой размер.
объект тривиально копируемый или
типовой макет (3.9) должен
занимают смежные байты памяти.
6 Если объект не является битовым полем или
подобъект базового класса нулевого размера,
адрес этого объекта является адресом
первого байта он занимает. Два
отдельные объекты, которые не являются ни
битовые поля или подобъекты базового класса
нулевого размера должен иметь
адреса.
(сноска) В соответствии с правилом «как если бы» реализация может хранить два объекта с одним и тем же машинным адресом или не сохранять объект вообще, если программа не может наблюдать разницу.
Дополнительные примечания:
10.1 / 8 относится к тому же таинственному содержанию в 5.10, но это также просто информативная заметка.
[Примечание:… подобъект базового класса может иметь нулевой размер (раздел 9); однако два подобъекта, которые имеют один и тот же тип класса и принадлежат к одному и тому же самому производному объекту, не должны размещаться по одному и тому же адресу (5.10). - конец примечания]
Похоже, что GCC гарантирует, что пустые базовые подобъекты одного типа получают уникальные адреса. Пример программы и выходных данных. Этого достаточно, чтобы гарантировать, что объекты данного типа однозначно идентифицируются по адресу. Это было бы сверх гарантий объектной модели C ++, §1.8. Конечно, это хорошая идея, но она не требуется Стандартом. Аналогично, платформа ABI может распространить эту гарантию на класс, в котором первый член имеет псевдоним пустой базы. Язык устанавливает минимальные требования для ABI; ABI может добавить функцию языка, а другие ABI могут последовать его примеру, и процесс наверстывания по Стандарту просто подвержен ошибкам.
Мой вопрос заключается в том, выполняет ли данное требование что-либо в контексте Стандарта, а не является ли оно полезным для пользователя в сочетании с другими гарантиями ABI. Свидетельство того, что такая гарантия с уникальным адресом была предназначена и опущена только случайно, также сделало бы это требование более значимым.
Чтобы подвести итог ответа (или, во всяком случае, моего заключения):
Требование теоретически ничего не гарантирует, так как в любом случае возможно гарантировать, что все объекты данного типа имеют разные адреса. Когда адрес пустого подобъекта базового класса вступает в конфликт с другим объектом (либо другой базой, либо членом), компилятор может просто назначить ему произвольное расположение в структуре. Поскольку правила стандартной компоновки описывают только расположение элементов данных (возможно, унаследованных), местоположения пустых баз по-прежнему не определены и, возможно, несовместимы между аналогичными классами стандартной компоновки. (Насколько я заметил, расположение непустых баз все еще не определено, и тогда неясно, что в данном случае подразумевается под «первым членом», но они должны быть согласованы в любом случае.)
На практике требование позволяет реализациям продолжать использовать существующие ABI, если они включают пустую оптимизацию базового класса. Существующие компиляторы могут отключить EBO, когда требование нарушено, чтобы избежать совпадения адреса базы с адресом первого члена. Если бы Стандарт не ограничивал программы таким образом, библиотеки и программы пришлось бы перекомпилировать с обновленными компиляторами C ++ 0x… не стоит!