Empty base optimization
Позволяет размеру пустого базового подобъекта быть нулевым.
Содержание |
Объяснение
Размер любого
объекта
или члена-подобъекта должен быть не менее 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)); }
|
Оптимизация пустого базового класса
обязательна
для
StandardLayoutType
s
для сохранения требования, чтобы указатель на объект стандартного размещения, преобразованный с помощью
|
(начиная с 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 Sizeof [expr.sizeof]
-
- 11 Классы [class]
-
- 11.4 Члены класса [class.mem]
- Стандарт C++20 (ISO/IEC 14882:2020):
-
- 7.6.10 Операторы равенства [expr.eq]
-
- 7.6.2.4 Оператор sizeof [expr.sizeof]
-
- 11 Классы [class]
-
- 11.4 Члены класса [class.mem]
- Стандарт C++17 (ISO/IEC 14882:2017):
-
- 8.10 Операторы равенства [expr.eq]
-
- 8.3.3 Оператор sizeof [expr.sizeof]
-
- 12 Классы [class]
-
- 12.2 Члены класса [class.mem]
- Стандарт C++14 (ISO/IEC 14882:2014):
-
- 5.10 Операторы равенства [expr.eq]
-
- 5.3.3 Оператор sizeof [expr.sizeof]
-
- 9 Классы [class]
-
- 9.2 Члены класса [class.mem]
- Стандарт C++11 (ISO/IEC 14882:2011):
-
- 5.10 Операторы равенства [expr.eq] (стр: 2)
-
- 5.3.3 Sizeof [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 Sizeof [expr.sizeof] (стр: 2)
-
- 9 Классы [class] (стр: 3)
Внешние ссылки
| More C++ Idioms/Empty Base Optimization — викиучебник |