Considérez les trois struct
s suivants:
class blub {
int i;
char c;
blub(const blub&) {}
};
class blob {
char s;
blob(const blob&) {}
};
struct bla {
blub b0;
blob b1;
};
Sur les plates-formes typiques où int
est de 4 octets, les tailles, les alignements et le remplissage total 1 sont les suivants:
struct size alignment padding
-------- ------ ----------- ---------
blub 8 4 3
blob 1 1 0
bla 12 4 6
Il n'y a pas de chevauchement entre le stockage des éléments blub
et blob
, même si la taille 1 blob
pourrait en principe "rentrer" dans le rembourrage de blub
.
C ++ 20 introduit l' no_unique_address
attribut, qui permet aux membres vides adjacents de partager la même adresse. Il permet également explicitement le scénario décrit ci-dessus d'utiliser le remplissage d'un membre pour en stocker un autre. De cppreference (soulignement le mien):
Indique que ce membre de données n'a pas besoin d'avoir une adresse distincte de tous les autres membres de données non statiques de sa classe. Cela signifie que si le membre a un type vide (par exemple Allocator sans état), le compilateur peut l'optimiser pour n'occuper aucun espace, comme s'il s'agissait d'une base vide. Si le membre n'est pas vide, tout remplissage de queue peut également être réutilisé pour stocker d'autres membres de données.
En effet, si nous utilisons cet attribut sur blub b0
la taille des bla
gouttes 8
, le blob
est en effet stocké dans le blub
comme vu sur godbolt .
Enfin, nous arrivons à ma question:
Quel texte dans les normes (C ++ 11 à C ++ 20) empêche ce chevauchement sans no_unique_address
, pour les objets qui ne sont pas trivialement copiables?
J'ai besoin d'exclure les objets trivialement copiables (TC) de ce qui précède, car pour les objets TC, il est autorisé de passer std::memcpy
d'un objet à un autre, y compris les sous-objets membres, et si le stockage était chevauché, cela se briserait (car tout ou partie du stockage pour le membre adjacent serait écrasé) 2 .
1 Nous calculons le remplissage simplement comme la différence entre la taille de la structure et la taille de tous ses membres constitutifs, récursivement.
2 Voilà pourquoi j'ai constructeurs de copie définis: pour faire blub
et blob
non trivialement copiable .