Namensräume
Varianten
Aktionen

Empty Base Optimierung

Von cppreference.com
< cpp‎ | Sprache
 
 
C++ Sprache
Allgemeine Themen
Kontrollfluss
Bedingte Ausführungsaussagen
if
Iterationsanweisungen (Schleifen)
for
Bereichs-for (C++11)
Sprunganweisungen
Funktionen
Funktionsdeklaration
Lambda-Funktionsausdruck
inline-Spezifizierer
Dynamische Ausnahmespezifikationen (bis C++17*)
noexcept-Spezifizierer (C++11)
Ausnahmen
Namensräume
Typen
Spezifizierer
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Speicherdauer-Spezifizierer
Initialisierung
Ausdrücke
Alternative Darstellungen
Literale
Boolesch - Ganzzahl - Gleitkommazahl
Zeichen - String - nullptr (C++11)
Benutzerdefinierte (C++11)
Dienstprogramme
Attribute (C++11)
Typen
typedef-Deklaration
Typalias-Deklaration (C++11)
Umwandlungen
Speicherzuweisung
Klassen
Klassenspezifische Funktionseigenschaften
explicit (C++11)
static

Spezielle Member-Funktionen
Templates
Sonstiges
 
 

Ermöglicht die Größe eines leeren Basis-Subobjekts auf Null zu setzen.

Inhalt

[bearbeiten] Erklärung

Die Größe jedes Objekts oder Member-Subobjekts muss mindestens 1 betragen, auch wenn der Typ ein leerer Klassentyp ist (d.h. eine Klasse oder Struktur, die keine nicht-statischen Datenmember hat), (es sei denn, mit [[no_unique_address]], siehe unten)(seit C++20) um sicherzustellen, dass die Adressen unterschiedlicher Objekte desselben Typs immer unterschiedlich sind.

Basisklassen-Subobjekte unterliegen jedoch keiner solchen Einschränkung und können aus dem Objektlayout vollständig herausoptimiert werden.

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));
}

Die Empty Base Optimierung ist verboten, wenn eine der leeren Basisklassen auch der Typ oder die Basis des Typs des ersten nicht-statischen Datenmembers ist, da die beiden Basis-Subobjekte desselben Typs innerhalb der Objektrepräsentation des am stärksten abgeleiteten Typs unterschiedliche Adressen haben müssen.

Ein typisches Beispiel für eine solche Situation ist die naive Implementierung von std::reverse_iterator (abgeleitet von der leeren Basis std::iterator), die den zugrundeliegenden Iterator (ebenfalls abgeleitet von std::iterator) als ihren ersten nicht-statischen Datenmember speichert.

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));
}

Wenn Mehrfachvererbung auftritt, sind die spezifischen Optimierungen compilerabhängig.

  • In MSVC wird die Null-Basis-Klassen-Optimierung mit und nur mit der letzten Null-Basis-Klasse angewendet. Für die restlichen Null-Basis-Klassen wird die Null-Basis-Optimierung nicht angewendet und ein Byte wird alloziert.
  • In GCC, unabhängig davon, wie viele leere Basisklassen existieren, wendet die leere Basisklassen-Optimierung die leere Basisklassen-Optimierung an, ohne Speicher zu alloziieren, und die Adresse der leeren Basisklasse ist dieselbe wie die erste Adresse des abgeleiteten Klassenobjekts.

Die Empty Base Optimierung ist für StandardLayoutTypes *erforderlich*, um die Anforderung aufrechtzuerhalten, dass ein Zeiger auf ein Standard-Layout-Objekt, der mittels reinterpret_cast konvertiert wird, auf seinen ersten Member zeigt. Deshalb beinhalten die Anforderungen für einen Standard-Layout-Typ "hat alle nicht-statischen Datenmember, die in derselben Klasse deklariert sind (entweder alle in der abgeleiteten oder alle in einer Basisklasse)" und "hat keine Basisklassen desselben Typs wie der erste nicht-statische Datenmember".

(seit C++11)

Leere Member-Subobjekte dürfen genauso wie leere Basen herausoptimiert werden, wenn sie das Attribut [[no_unique_address]] verwenden. Das Nehmen der Adresse eines solchen Members ergibt eine Adresse, die gleich der Adresse eines anderen Members desselben Objekts sein kann.

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

[bearbeiten] Hinweise

Die Empty Base Optimierung wird häufig von Allocator-aware Standardbibliotheksklassen (std::vector, std::function, std::shared_ptr usw.) verwendet, um keinen zusätzlichen Speicher für ihren Allocator-Member zu belegen, wenn der Allocator zustandslos ist. Dies wird erreicht, indem einer der erforderlichen Datenmember (z.B. der begin-, end- oder capacity-Zeiger für vector) in einem Äquivalent zu boost::compressed_pair zusammen mit dem Allocator gespeichert wird.

[bearbeiten] Referenzen

  • C++23 Standard (ISO/IEC 14882:2024)
  • 7.6.10 Gleichheitsoperatoren [expr.eq]
  • 7.6.2.5 Sizeof [expr.sizeof]
  • 11 Klassen [class]
  • 11.4 Klassenmember [class.mem]
  • C++20 Standard (ISO/IEC 14882:2020)
  • 7.6.10 Gleichheitsoperatoren [expr.eq]
  • 7.6.2.4 Sizeof [expr.sizeof]
  • 11 Klassen [class]
  • 11.4 Klassenmember [class.mem]
  • C++17 Standard (ISO/IEC 14882:2017)
  • 8.10 Gleichheitsoperatoren [expr.eq]
  • 8.3.3 Sizeof [expr.sizeof]
  • 12 Klassen [class]
  • 12.2 Klassenmember [class.mem]
  • C++14 Standard (ISO/IEC 14882:2014)
  • 5.10 Gleichheitsoperatoren [expr.eq]
  • 5.3.3 Sizeof [expr.sizeof]
  • 9 Klassen [class]
  • 9.2 Klassenmember [class.mem]
  • C++11 Standard (ISO/IEC 14882:2011)
  • 5.10 Gleichheitsoperatoren [expr.eq] (p: 2)
  • 5.3.3 Sizeof [expr.sizeof] (p: 2)
  • 9 Klassen [class] (p: 4,7)
  • 9.2 Klassenmember [class.mem] (p: 20)
  • C++98 Standard (ISO/IEC 14882:1998)
  • 5.10 Gleichheitsoperatoren [expr.eq] (p: 2)
  • 5.3.3 Sizeof [expr.sizeof] (p: 2)
  • 9 Klassen [class] (p: 3)

[bearbeiten] Externe Links

More C++ Idioms/Empty Base Optimization — Ein Wikibuch