Empty Base Optimierung
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 |
(seit C++11) |
|
Leere Member-Subobjekte dürfen genauso wie leere Basen herausoptimiert werden, wenn sie das Attribut Führen Sie diesen Code aus 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 |