Namespaces
Variants

Empty base optimization

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

Permet à la taille d'un sous-objet de base vide d'être nulle.

Table des matières

Explication

La taille de tout objet ou sous-objet membre doit être d'au moins 1 même si le type est une classe vide (c'est-à-dire une classe ou structure sans membres de données non statiques), (sauf avec [[ no_unique_address ]] , voir ci-dessous) (depuis C++20) afin de garantir que les adresses d'objets distincts du même type soient toujours distinctes.

Cependant, les sous-objets de classe de base ne sont pas soumis à cette contrainte et peuvent être complètement optimisés dans la disposition de l'objet :

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));
}
**Traductions effectuées :** - "Run this code" → "Exécuter ce code" - Les commentaires en anglais dans le code C++ ont été conservés comme demandé - Toutes les balises HTML et attributs préservés - Le code C++ dans les balises `
` et `` n'a pas été modifié
- Les termes spécifiques C++ (struct, static_assert, sizeof, etc.) conservés en anglais

L'optimisation de base vide est interdite si l'une des classes de base vides est également le type ou la base du type du premier membre de données non statique, car les deux sous-objets de base de même type doivent avoir des adresses différentes dans la représentation de l'objet du type le plus dérivé.

Un exemple typique d'une telle situation est l'implémentation naïve de std::reverse_iterator (dérivée de la classe de base vide std::iterator ), qui contient l'itérateur sous-jacent (également dérivé de std::iterator ) comme son premier membre de données non statique.

struct Base {}; // classe vide
struct Derived1 : Base
{
    int i;
};
struct Derived2 : Base
{
    Base c; // Base, occupe 1 octet, suivi du remplissage pour i
    int i;
};
struct Derived3 : Base
{
    Derived1 c; // dérivé de Base, occupe sizeof(int) octets
    int i;
};
int main()
{
    // l'optimisation de base vide ne s'applique pas,
    // la base occupe 1 octet, le membre Base occupe 1 octet
    // suivi de 2 octets de remplissage pour satisfaire les exigences d'alignement de int
    static_assert(sizeof(Derived2) == 2*sizeof(int));
    // l'optimisation de base vide ne s'applique pas,
    // la base prend au moins 1 octet plus le remplissage
    // pour satisfaire l'exigence d'alignement du premier membre (dont
    // l'alignement est le même que int)
    static_assert(sizeof(Derived3) == 3*sizeof(int));
}

L'optimisation de base vide est requise pour les StandardLayoutType s afin de maintenir l'exigence selon laquelle le pointeur vers un objet de mise en page standard, converti à l'aide de reinterpret_cast , pointe vers son membre initial, ce qui explique pourquoi les exigences pour un type de mise en page standard incluent "a tous les membres de données non statiques déclarés dans la même classe (soit tous dans la classe dérivée, soit tous dans une classe de base)" et "n'a pas de classes de base du même type que le premier membre de données non statique".

(depuis C++11)

Les sous-objets membres vides sont autorisés à être optimisés tout comme les bases vides s'ils utilisent l'attribut [[ no_unique_address ]] . Prendre l'adresse d'un tel membre donne une adresse qui peut être égale à l'adresse d'un autre membre du même objet.

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));
}
(depuis C++20)

Notes

L'optimisation de base vide est couramment utilisée par les classes de la bibliothèque standard compatibles avec les allocateurs ( std::vector , std::function , std::shared_ptr , etc.) pour éviter d'occuper un espace de stockage supplémentaire pour son membre allocateur si celui-ci est sans état. Ceci est réalisé en stockant l'un des membres de données requis (par exemple, begin , end , ou capacity pointer pour le vector ) dans un équivalent de boost::compressed_pair avec l'allocateur.

Dans MSVC, l'optimisation des classes de base vides n'est pas entièrement conforme aux exigences standard ( Pourquoi l'optimisation des classes de base vides (EBO) ne fonctionne-t-elle pas dans MSVC ? ).

Références

  • Norme C++23 (ISO/CEI 14882:2024) :
  • 7.6.10 Opérateurs d'égalité [expr.eq]
  • 7.6.2.5 Sizeof [expr.sizeof]
  • 11 Classes [class]
  • 11.4 Membres de classe [class.mem]
  • Norme C++20 (ISO/CEI 14882:2020) :
  • 7.6.10 Opérateurs d'égalité [expr.eq]
  • 7.6.2.4 Sizeof [expr.sizeof]
  • 11 Classes [class]
  • 11.4 Membres de classe [class.mem]
  • Norme C++17 (ISO/CEI 14882:2017) :
  • 8.10 Opérateurs d'égalité [expr.eq]
  • 8.3.3 Sizeof [expr.sizeof]
  • 12 Classes [class]
  • 12.2 Membres de classe [class.mem]
  • Norme C++14 (ISO/CEI 14882:2014) :
  • 5.10 Opérateurs d'égalité [expr.eq]
  • 5.3.3 Sizeof [expr.sizeof]
  • 9 Classes [class]
  • 9.2 Membres de classe [class.mem]
  • Norme C++11 (ISO/CEI 14882:2011) :
  • 5.10 Opérateurs d'égalité [expr.eq] (p: 2)
  • 5.3.3 Sizeof [expr.sizeof] (p: 2)
  • 9 Classes [class] (p: 4,7)
  • 9.2 Membres de classe [class.mem] (p: 20)
  • Norme C++98 (ISO/CEI 14882:1998) :
  • 5.10 Opérateurs d'égalité [expr.eq] (p : 2)
  • 5.3.3 Sizeof [expr.sizeof] (p : 2)
  • 9 Classes [class] (p : 3)

Liens externes

More C++ Idioms/Empty Base Optimization — Un wikibook