Der C++-Standard legt dies fest:
- Objekte haben eine Ausrichtungsanforderung, deren Größe ein Vielfaches davon ist (wenn also
int
4 Bytes breit ist, ist eine Ausrichtung von 1, 2 oder 4 Bytes erforderlich, je nach Implementierung).
- Mitgliedsobjekte (wenn sie nicht durch Zugriffsspezifikationen wie
public
) werden alle in der Reihenfolge zugewiesen, in der sie deklariert werden
- und sie werden unter Berücksichtigung ihrer Ausrichtungsanforderungen zugewiesen.
Die Norm besagt also nicht, dass die Klasse eine Größe von 12 Byte haben sollte.
Aber es fait sagen, dass b
sollte zugewiesen werden nach a
und dass c
sollte zugewiesen werden nach b
.
Auf einer Plattform, auf der int
4 Bytes breit ist und eine 4-Byte-Ausrichtung erfordert, bleiben 12 Bytes als kleinste gültige Größe übrig:
a
nimmt die ersten 4 Bytes
b
benötigt ein Byte
c
benötigt 4 Bytes, sondern muss an einer 4-Byte-Grenze zugewiesen werden. b
ein Byte beendet Vergangenheit eine solche Grenze, so dass die nächste gültige Position, an der c
at wird durch Einfügen von 3 Bytes Füllmaterial gefunden.
Die Gesamtgröße der Klasse entspricht also der Größe der Mitglieder (4 + 1 + 4 = 9) plus drei Bytes Füllmaterial, also insgesamt 12.
Es gibt noch eine weitere Regel, die hier keine Auswirkung hat, die aber wichtig wäre, wenn Sie die Mitglieder in der Reihenfolge definiert hätten a, c, b
stattdessen.
Die enthaltende Klasse ( A
) erbt die Ausrichtungsanforderung von dem am strengsten ausgerichteten Mitgliedsobjekt. Das heißt, weil es ein int
hat es die gleichen Ausrichtungsanforderungen wie ein int
tut. Und da die Gesamtgröße des Objekts ein Vielfaches der Ausrichtungsanforderung sein muss, muss eine Klasse, die die Mitglieder in der Reihenfolge a, b, c
würde immer noch 12 Bytes Speicherplatz benötigen. Es würde einfach die 3 Bytes Füllung an das Ende der Klasse verschieben, anstatt zwischen b
y c
.
In einigen anderen Fällen kann die Neuordnung der Mitglieder in absteigender Reihenfolge der Größe jedoch manchmal die Größe einer Klasse zu reduzieren.
Nehmen wir an, wir hätten stattdessen eine Klasse wie diese:
class B {
char a;
double b;
int c;
};
Dies hätte 24 Byte Speicherplatz erfordert (1 Byte für a
, 8 Byte für b
und 4 Bytes für c
sondern auch, um sicherzustellen b
auf einer 8-Byte-Grenze landet, bräuchten wir 7 Bytes zum Auffüllen zwischen a
y b
und um sicherzustellen, dass die gesamte Klasse am Ende ein Vielfaches von 8 ist, benötigen wir weitere 4 Bytes nach c
.
Aber die Mitglieder werden nach ihrer Größe neu geordnet, etwa so:
class B {
double b;
int c;
char a;
};
führt zu einer Klasse, die nur 16 Bytes benötigt:
die gleichen 1 + 4 + 8 Bytes für die Mitgliedsobjekte selbst, aber jetzt c
bereits an einer 4-Byte-Grenze ausgerichtet ist (weil es nach b
die an einer 8-Byte-Grenze endet) und a
braucht nie eine Ausrichtung, so dass die einzige Ausrichtung, die wir brauchen, darin besteht, sicherzustellen, dass B
hat eine Größe, die ein Vielfaches von 8 ist. Die Mitglieder benötigen 13 Bytes, also können wir 3 Bytes Füllung hinzufügen, und die Klasse ist am Ende 16 Bytes groß, 33% kleiner als die erste Version.