Давайте посмотрим на структуру данных B:
struct A {};
struct B : public A {
A _first;
};
Какой у нее размер? С учетом того, что даже у пустой структуры размер будет, как минимум, 1 байт. И что в C++ есть empty base class optimization.
То, что B наследуется от пустого A благодаря empty base class optimization не увеличивает размер B. Т.е. размер B будет определяться размером поля B::_first, а это один байт. Следовательно, sizeof(B) должен быть равен единице.
На самом деле нет.
Дело в адресах для объекта B и для его поля B::_first:
B b;
A * p1 = &b; // Это легально т.к. B есть A благодаря наследованию.
A * p2 = &b._first;
assert(p1 != p2);
Объект типа B является объектом типа A из-за наследования. Соответственно, адрес объекта типа B будет и адресом объекта типа A.
Внутри типа B есть еще один объект типа A. И у него так же есть свой адрес.
При этом объект B и его поле B::_first -- это два разных объекта типа A.
А в C++ у двух разных объектов одного типа не может быть одинаковых адресов.
Поэтому в показанном примере компилятор не может применить для типа B оптимизацию пустой базы, что и добавляет специальное выравнивание для поля B::_first, чтобы эти адреса оказались разными. Тем самым увеличивая размер B.
Убедиться в этом можно на wandbox - цынк
Информация об этой особенности C++ найдена здесь.
PS. Какой практический смысл у этой информации? Вероятно, никакого. Но это лишняя иллюстрация того, сколько же разных нюансов приходится учитывать при развитии C++.
Комментариев нет:
Отправить комментарий