Empty base optimization
Permite que el tamaño de un subobjeto base vacío sea cero.
Contenidos |
Explicación
El tamaño de cualquier
objeto
o subobjeto miembro debe ser al menos 1 incluso si el tipo es una
class type
vacía (es decir, una clase o struct que no tiene miembros de datos no estáticos),
(a menos que se use
[[
no_unique_address
]]
, ver más abajo)
(since C++20)
para poder garantizar que las direcciones de objetos distintos del mismo tipo sean siempre diferentes.
Sin embargo, los subobjetos de la clase base no tienen esta restricción y pueden ser completamente optimizados en el diseño del objeto:
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)); }
La optimización de base vacía está prohibida si una de las clases base vacías es también el tipo o la base del tipo del primer miembro de datos no estático, ya que se requiere que los dos subobjetos base del mismo tipo tengan direcciones diferentes dentro de la representación del objeto del tipo más derivado.
Un ejemplo típico de tal situación es la implementación ingenua de std::reverse_iterator (derivada de la clase base vacía std::iterator ), que mantiene el iterador subyacente (también derivado de std::iterator ) como su primer miembro de datos no estático.
struct Base {}; // clase vacía struct Derived1 : Base { int i; }; struct Derived2 : Base { Base c; // Base, ocupa 1 byte, seguido de relleno para i int i; }; struct Derived3 : Base { Derived1 c; // derivada de Base, ocupa sizeof(int) bytes int i; }; int main() { // la optimización de base vacía no se aplica, // la base ocupa 1 byte, el miembro Base ocupa 1 byte // seguido de 2 bytes de relleno para satisfacer los requisitos de alineación de int static_assert(sizeof(Derived2) == 2*sizeof(int)); // la optimización de base vacía no se aplica, // la base ocupa al menos 1 byte más el relleno // para satisfacer el requisito de alineación del primer miembro (cuya // alineación es la misma que int) static_assert(sizeof(Derived3) == 3*sizeof(int)); }
|
La optimización de base vacía es
requerida
para los
StandardLayoutType
s
para mantener el requisito de que el puntero a un objeto de diseño estándar, convertido usando
|
(desde C++11) |
|
Se permite optimizar los subobjetos de miembro vacíos al igual que las bases vacías si utilizan el atributo
Ejecutar este código
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)); } |
(desde C++20) |
Notas
La optimización de base vacía es comúnmente utilizada por las clases de la biblioteca estándar conscientes del asignador (
std::vector
,
std::function
,
std::shared_ptr
, etc) para evitar ocupar almacenamiento adicional para su miembro asignador si el asignador no tiene estado. Esto se logra almacenando uno de los miembros de datos requeridos (por ejemplo,
begin
,
end
, o
capacity
pointer para el
vector
) en un equivalente de
boost::compressed_pair
con el asignador.
En MSVC, la optimización de clases base vacías no es completamente conforme con los requisitos del estándar ( Why is the empty base class optimization (EBO) is not working in MSVC? ).
Referencias
- Estándar C++23 (ISO/IEC 14882:2024):
-
- 7.6.10 Operadores de igualdad [expr.eq]
-
- 7.6.2.5 Sizeof [expr.sizeof]
-
- 11 Clases [class]
-
- 11.4 Miembros de clase [class.mem]
- Estándar C++20 (ISO/IEC 14882:2020):
-
- 7.6.10 Operadores de igualdad [expr.eq]
-
- 7.6.2.4 Sizeof [expr.sizeof]
-
- 11 Clases [class]
-
- 11.4 Miembros de clase [class.mem]
- Estándar C++17 (ISO/IEC 14882:2017):
-
- 8.10 Operadores de igualdad [expr.eq]
-
- 8.3.3 Sizeof [expr.sizeof]
-
- 12 Clases [class]
-
- 12.2 Miembros de clase [class.mem]
- Estándar C++14 (ISO/IEC 14882:2014):
-
- 5.10 Operadores de igualdad [expr.eq]
-
- 5.3.3 Sizeof [expr.sizeof]
-
- 9 Clases [class]
-
- 9.2 Miembros de clase [class.mem]
- Estándar C++11 (ISO/IEC 14882:2011):
-
- 5.10 Operadores de igualdad [expr.eq] (p: 2)
-
- 5.3.3 Sizeof [expr.sizeof] (p: 2)
-
- 9 Clases [class] (p: 4,7)
-
- 9.2 Miembros de clase [class.mem] (p: 20)
- Estándar C++98 (ISO/IEC 14882:1998):
-
- 5.10 Operadores de igualdad [expr.eq] (p: 2)
-
- 5.3.3 Sizeof [expr.sizeof] (p: 2)
-
- 9 Clases [class] (p: 3)
Enlaces externos
| More C++ Idioms/Empty Base Optimization — Un wikilibro |