Réponse courte (pour la partie C++ de la question) : Le site ABI Itanium pour C++ interdit, pour des raisons historiques, d'utiliser le rembourrage de queue d'un sous-objet de base de type POD. Notez que C++11 ne comporte pas une telle interdiction. La règle pertinente 3.9/2 qui permet aux types trivialement copiables d'être copiés via leur représentation sous-jacente exclut explicitement les sous-objets de base.
Longue réponse : Je vais essayer de traiter C++11 et C en même temps.
- La disposition des
S1
doit inclure un rembourrage, puisque S1::a
doivent être alignés pour int
et un tableau S1[N]
consiste en des objets alloués de manière contiguë de type S1
chacun d'entre eux a
Le membre doit être tellement aligné.
- En C++, les objets d'un type trivialement copiable
T
qui ne sont pas des sous-objets de base peuvent être traités comme des tableaux de sizeof(T)
(c'est-à-dire que vous pouvez convertir un pointeur d'objet en un octet de type unsigned char *
et de traiter le résultat comme un pointeur vers le premier élément d'un fichier unsigned char[sizeof(T)]
et la valeur de ce tableau détermine l'objet). Puisque tous les objets en C sont de ce type, ceci explique que S2
pour C et C++.
- Les cas intéressants restant pour le C++ sont :
- les sous-objets de base, qui ne sont pas soumis à la règle ci-dessus (cf. C++11 3.9/2), et
- tout objet qui n'est pas de type trivialement copiable.
Pour 3.1, il existe en effet des "optimisations de disposition de base" courantes et populaires dans lesquelles les compilateurs "compressent" les membres de données d'une classe dans les sous-objets de base. Ceci est plus frappant lorsque la classe de base est vide (∞% de réduction de taille !), mais s'applique plus généralement. Cependant, l'ABI Itanium pour C++ dont j'ai donné le lien plus haut et que de nombreux compilateurs mettent en œuvre interdit une telle compression de remplissage de queue lorsque le type de base respectif est POD (et POD signifie trivialement copiable et standard-layout).
Pour la version 3.2, la même partie de l'ABI de l'Itanium s'applique, bien que je ne pense pas que la norme C++11 rende obligatoire l'utilisation d'un code source arbitraire, non trivialement copiable. membre doivent avoir la même taille qu'un objet complet du même type.
La réponse précédente est conservée comme référence.
Je crois que c'est parce que S1
est une mise en page standard, et donc, pour une raison quelconque, l'option S1
-subjectif de S3
reste intacte. Je ne suis pas sûr que ce soit mandaté par la norme.
Cependant, si nous nous tournons S1
dans une disposition non standard, nous observons une optimisation de la disposition :
struct EB { };
struct S1 : EB { // not standard-layout
EB eb;
int a;
char b;
};
struct S3 : S1 {
char c;
};
Maintenant sizeof(S1) == sizeof(S3) == 12
sur ma plateforme. Démonstration en direct .
Et voici un Un exemple plus simple :
struct S1 {
private:
int a;
public:
char b;
};
struct S3 : S1 {
char c;
};
L'accès mixte rend S1
une mise en page non standard. (Maintenant sizeof(S1) == sizeof(S3) == 8
.)
Mise à jour : Le facteur déterminant semble être trivialité ainsi que la standard-layoutness, c'est-à-dire que la classe doit être POD. La classe non-POD standard-layout suivante est optimisable base-layout :
struct S1 {
~S1(){}
int a;
char b;
};
struct S3 : S1 {
char c;
};
Encore une fois sizeof(S1) == sizeof(S3) == 8
. Démo
0 votes
Cela ne signifie certainement pas que le compilateur l'a conçu de cette manière.
2 votes
Il faut encore l'aligner correctement lorsque vous faites un tableau de ces structures. Cela nécessite un remplissage supplémentaire à la fin.
0 votes
@HansPassant : Cela n'explique pas pourquoi
S3
ne peut pas tenir dans 8 octets...3 votes
Donc vous attendez du compilateur qu'il gère
S1
différemment selon qu'il fait partie deS2
ou apparaît séparément ?0 votes
À tous ceux qui ont mentionné l'alignement des données, j'ai répondu à votre point dans la dernière phrase de la question. Le compilateur pourrait faire tenir S2 ou S3 dans 8 octets sans rompre les contraintes d'alignement.
0 votes
Je pense avoir trouvé la réponse (j'ai eu de l'aide).
2 votes
C'est une question intéressante à laquelle les concepteurs de langage doivent réfléchir. Lorsque nous avons implémenté Java pour IBM iSeries, nous avons constaté que si nous "emballions" les structures (tout en conservant l'alignement que le matériel préférait), nous économisions suffisamment d'espace de stockage pour obtenir une amélioration des performances de l'ordre de 10 %, grâce à une meilleure utilisation du cache et à une réduction de la charge de la collecte des déchets. (Bien entendu, la norme Java n'impose aucune restriction sur l'ordre ou la disposition des variables dans un objet, ce qui nous permettait de nous en tirer à bon compte, alors que l'implémenteur C++ n'a pas cette chance).
0 votes
@HotLicks En effet, j'essaie d'obtenir des informations emballées correctement pour améliorer l'utilisation du cache. Il semble que le C et le C++ perdent beaucoup d'espace ici et j'essaie de comprendre pourquoi.