Стандартная компоновка C++
Я просматривал отличные статьи о классах C++ POD, Trivial и Standard Layout. Одно свойство, которое я не совсем понял в отношении стандартного макета, заключается в следующем:
A standard layout has no base classes of the same type as the first
non-static data member
Таким образом, следующее не будет стандартным макетом, так как в нем первый член совпадает с базовым классом.
struct NonStandardLayout3 : StandardLayout1 {
StandardLayout1 x; // first member cannot be of the same type as base
};
Но с точки зрения производительности и свойств как вышеприведенная структура отличается от
struct StandardLayout5 : StandardLayout1 {
int x;
StandardLayout1 y; // can have members of base type if they're not the first
};
что является исправлением вышеупомянутого.
1 ответ
Причина заключается в том, что стандартные типы макетов эффективно предписывают "пустую оптимизацию базового класса", когда базовые классы без элементов данных не занимают места и имеют тот же адрес, что и первый элемент данных (если есть) производного класса.
Однако попытка сделать это, когда базовый класс имеет тот же тип, что и первый член данных, нарушает модель памяти C++, которая требует, чтобы разные объекты одного типа имели разные адреса.
Из ИСО / МЭК 14882:2011 1.8 [intro.object]/6:
Два объекта, которые не являются битовыми полями, могут иметь один и тот же адрес, если один является подобъектом другого, или если хотя бы один является подобъектом базового класса нулевого размера, и они имеют разные типы; в противном случае они должны иметь разные адреса
эффективно назначая пустой базовый класс, 9.2 [class.mem] /20:
Указатель на объект структуры стандартной компоновки, соответствующим образом преобразованный с использованием
reinterpret_cast
, указывает на свой начальный элемент (или, если этот элемент является битовым полем, то на модуль, в котором он находится), и наоборот.
Это было бы невозможно для следующих типов (Type1
а также Type2
) быть совместимым с макетом (хотя в противном случае он будет стандартным классом макета) без этого ограничения.
struct S1 {};
struct S2 {};
struct Type1 : S1 {
S1 s;
int k;
};
struct Type2 : S1 {
S2 s;
int m;
};