Les dimensions size
et align
représentent la taille et l'alignement de la classe lorsqu'elle est utilisée en tant que type complet. C'est-à-dire, si vous créez des objets dont le type complet est ce type (comme définir des variables de ce type, ou utiliser ce type avec new
).
La taille est simplement le nombre d'octets qu'elle occupe. Donc size=16
signifie lorsqu'il est utilisé en tant que type complet, il occupe toujours 16 octets.
L'alignement vous indique où l'objet peut être placé: align=8
signifie que l'adresse de l'objet doit être un multiple entier de 8.
Le base size
et base align
donner la taille et l'alignement dans le cas où la classe est utilisée comme classe de base. La raison pour laquelle ils sont différents est que la norme C++ permet aux objets d'utiliser moins de remplissage lorsqu'ils sont utilisés en tant que classe de base. Alors regardons spécifiquement votre exemple (je suppose que vous avez réellement le int
devant le double
dans le premier cas). J'omets également le public
et private
parce qu'ici ils ne changent rien (si vous aviez des membres de données publics ou privés, pourrait en principe changer quelque chose, mais je ne sais pas si n'importe quel compilateur en profite). Je devine également la taille et l'alignement de int
et double
(en fait les valeurs que je suppose sont un choix assez commun, et expliquent les valeurs que vous obtenez).
Ainsi, dans le premier cas (je suppose) que vous avez
class A
{
int m_number;
double m_nothing;
};
Maintenant int
a la taille et l'alignement 4
et double a la taille et l'alignement 8
. Alors, faisons le travail du compilateur et construisons notre classe. D'abord, nous avons m_number
, qui occupe 4 octets. Nous devons mettre les membres dans l'ordre donné, si m_number
va au début de A
:
iiii
Jusqu'à présent, nous avons la taille 4 (quatre octets pour l'int) et l'alignement 4 (car int a l'alignement 4). Mais maintenant nous devons ajouter un double (taille et alignement 8).Puisque directement après l'int, nous sommes à l'adresse (relative) 4, nous ne sommes pas correctement alignés pour le double, donc nous devons ajouter 4 padding octets (que je marquerai avec *
) pour obtenir un multiple de 8 Nous obtenons ainsi pour notre classe:
iiii****dddddddd
Maintenant, si la classe est utilisée comme classe de base, nous avons terminé. Ainsi, nous avons base size=16
et base align=8
(nous avons besoin d'un alignement de 8 pour obtenir le double alignement correctement).
Pour l'objet complet, il y a une autre considération: La norme exige que dans les tableaux, les objets se suivent sans espace entre les deux. C'est-à-dire que le premier octet après l'objet doit être correctement aligné pour l'objet suivant. Ce qui signifie finalement que la taille de l'objet complet doit être un multiple de son alignement.
Maintenant, la disposition des objets que nous avons trouvée répond déjà à cette exigence. Par conséquent, nous pouvons l'utiliser également pour l'objet complet. Par conséquent, nous obtenons size=16
et align=8
pour l'objet complet.
Considérons maintenant le cas où l'ordre est inversé:
class A
{
double m_nothing;
int m_number;
};
Maintenant, nous devons commencer par le double
:
dddddddd
Ensuite, nous devons ajouter le int
. Comme il se trouve, la place à côté libre est déjà aligné correctement pour un int
, on peut donc tout simplement l'ajouter:
ddddddddiiii
Maintenant, pour l'utilisation comme objet de base, nous sommes prêts. Comme vous pouvez le voir, nous n'avions besoin que de 12 octets, donc base size=12
. Bien sûr, pour que le double
soit correctement aligné, l'objet doit à nouveau commencer à une adresse qui est un multiple de 8. Nous avons donc base align=8
.
Cependant, pour le poursuivre en justice comme objet complet, nous constatons maintenant que l'adresse suivante serait en position 12, qui est pas correctement aligné pour le membre double
. Par conséquent, nous devons ajouter des octets de remplissage jusqu'à atteindre une adresse alignée correctement à nouveau: Comme vous pouvez le voir
ddddddddiiii****
, maintenant nous avons besoin de 16 octets, size=16
ainsi. Nous avons encore align=8
en raison du double. Notez que l'exigence d'alignement peut affecter considérablement la taille d'une classe. Considérons par exemple les deux types suivants:
struct S1
{
char c1;
double d1;
char c2;
double d2;
char c3;
};
struct S2
{
double d1;
double d2;
char c1;
char c2;
char c3;
};
Bien que les deux contiennent les mêmes membres, S1
seront les tailles et les alignements ci-dessus ont une taille totale (non-base) de 40, alors que la taille totale de S2
sera juste 24.En effet, les objets de type S1
seront, comme objet complet, regardez comme
c*******ddddddddc*******ddddddddc*******
tandis que ceux de type S2
ressemblera
ddddddddddddddddccc*****
Ainsi, la ligne de fond est que les membres avec l'exigence d'alignement le plus élevé devrait toujours venir en premier.
Notez également que sizeof
renvoie la taille des objets complets, c'est-à-dire que le vidage de la hiérarchie de classes appelle size
.
Je pense que vous avez oublié de changer un peu la classe. – chris
Ohh désolé! Dans le deuxième exemple, j'ai échangé la variable de deux membres. – user19840919