Оптимизация пустого базового класса
Позволяет размеру пустого базового подобъекта быть равным нулю.
Пояснение
Размер любого объекта или подобъекта-члена должен быть не меньше 1, даже если тип является пустым типом класса (то есть классом или структурой без нестатических членов данных), (если не используется [[no_unique_address]], см. ниже)(начиная с C++20), чтобы можно было гарантировать, что адреса различных объектов одного и того же типа всегда различны.
Однако на подобъекты базовых классов это ограничение не распространяется, поэтому их можно полностью исключить из размещения объекта:
struct Base {}; // empty class
struct Derived1 : Base
{
int i;
};
int main()
{
// the size of any object of empty class type is at least 1
static_assert(sizeof(Base) >= 1);
// empty base optimization applies
static_assert(sizeof(Derived1) == sizeof(int));
}
Оптимизация пустого базового класса запрещена, если один из пустых базовых классов также является типом первого нестатического члена данных или базовым классом этого типа, поскольку два подобъекта базового класса одного типа должны иметь разные адреса в представлении объекта наиболее производного типа.
Типичный пример такой ситуации — наивная реализация std::reverse_iterator (производного от пустого базового класса std::iterator), которая хранит базовый итератор (также производный от std::iterator) в качестве своего первого нестатического члена данных.
struct Base {}; // empty class
struct Derived1 : Base
{
int i;
};
struct Derived2 : Base
{
Base c; // Base, occupies 1 byte, followed by padding for i
int i;
};
struct Derived3 : Base
{
Derived1 c; // derived from Base, occupies sizeof(int) bytes
int i;
};
int main()
{
// empty base optimization does not apply,
// base occupies 1 byte, Base member occupies 1 byte
// followed by 2 bytes of padding to satisfy int alignment requirements
static_assert(sizeof(Derived2) == 2*sizeof(int));
// empty base optimization does not apply,
// base takes up at least 1 byte plus the padding
// to satisfy alignment requirement of the first member (whose
// alignment is the same as int)
static_assert(sizeof(Derived3) == 3*sizeof(int));
}
| Для типов стандартной компоновки оптимизация пустого базового класса обязательна, чтобы сохранить требование, согласно которому указатель на объект стандартной компоновки, преобразованный с помощью | (начиная с C++11) |
| Пустые подобъекты-члены разрешено исключать из размещения так же, как и пустые базовые классы, если для них используется атрибут struct Empty {}; // empty class
struct X
{
int i;
[[no_unique_address]] Empty e;
};
int main()
{
// the size of any object of empty class type is at least 1
static_assert(sizeof(Empty) >= 1);
// empty member optimized out:
static_assert(sizeof(X) == sizeof(int));
}
| (начиная с C++20) |
Примечания
Оптимизация пустого базового класса часто используется классами стандартной библиотеки, учитывающими аллокатор (std::vector, std::function, std::shared_ptr и т. д.), чтобы не занимать дополнительное место для члена-аллокатора, если аллокатор не имеет состояния. Для этого один из обязательных членов данных (например, указатель begin, end или capacity для vector) хранится вместе с аллокатором в объекте, эквивалентном boost::compressed_pair.
В MSVC оптимизация пустого базового класса не полностью соответствует требованиям стандарта (Почему оптимизация пустого базового класса (EBO) не работает в MSVC?).
Ссылки
- Стандарт C++23 (ISO/IEC 14882:2024):
- 7.6.10 Операторы равенства [expr.eq]
- 7.6.2.5 Размер [expr.sizeof]
- 11 Классы [class]
- 11.4 Члены классов [class.mem]
- Стандарт C++20 (ISO/IEC 14882:2020):
- 7.6.10 Операторы равенства [expr.eq]
- 7.6.2.4 Размер [expr.sizeof]
- 11 Классы [class]
- 11.4 Члены классов [class.mem]
- Стандарт C++17 (ISO/IEC 14882:2017):
- 8.10 Операторы равенства [expr.eq]
- 8.3.3 Размер [expr.sizeof]
- 12 Классы [class]
- 12.2 Члены классов [class.mem]
- Стандарт C++14 (ISO/IEC 14882:2014):
- 5.10 Операторы равенства [expr.eq]
- 5.3.3 Размер [expr.sizeof]
- 9 Классы [class]
- 9.2 Члены классов [class.mem]
- Стандарт C++11 (ISO/IEC 14882:2011):
- 5.10 Операторы равенства [expr.eq] (п: 2)
- 5.3.3 Размер [expr.sizeof] (п: 2)
- 9 Классы [class] (п: 4,7)
- 9.2 Члены классов [class.mem] (п: 20)
- Стандарт C++98 (ISO/IEC 14882:1998):
- 5.10 Операторы равенства [expr.eq] (п: 2)
- 5.3.3 Размер [expr.sizeof] (п: 2)
- 9 Классы [class] (п: 3)
Внешние ссылки
| Больше идиом C++/Оптимизация пустого базового класса — книга на Wikibooks |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/language/ebo