Considera le seguenti tre struct
s:
class blub {
int i;
char c;
blub(const blub&) {}
};
class blob {
char s;
blob(const blob&) {}
};
struct bla {
blub b0;
blob b1;
};
Su piattaforme tipiche in cui int
sono presenti 4 byte, le dimensioni, gli allineamenti e il riempimento totale 1 sono i seguenti:
struct size alignment padding
-------- ------ ----------- ---------
blub 8 4 3
blob 1 1 0
bla 12 4 6
Non vi è alcuna sovrapposizione tra la memoria dei membri blub
e blob
, anche se la dimensione 1 blob
potrebbe in linea di principio "adattarsi" all'imbottitura di blub
.
C ++ 20 introduce l' no_unique_address
attributo, che consente ai membri vuoti adiacenti di condividere lo stesso indirizzo. Inoltre, consente esplicitamente lo scenario sopra descritto di utilizzare il riempimento di un membro per memorizzarne un altro. Da cppreference (sottolineatura mia):
Indica che questo membro di dati non deve necessariamente avere un indirizzo distinto da tutti gli altri membri di dati non statici della sua classe. Ciò significa che se il membro ha un tipo vuoto (ad es. Allocatore senza stato), il compilatore può ottimizzarlo per non occupare spazio, proprio come se fosse una base vuota. Se il membro non è vuoto, è possibile riutilizzare qualsiasi padding di coda per memorizzare altri membri di dati.
In effetti, se usiamo questo attributo su blub b0
, la dimensione di bla
scende a 8
, quindi blob
è effettivamente memorizzato nel blub
come visto su godbolt .
Infine, arriviamo alla mia domanda:
Quale testo negli standard (da C ++ 11 a C ++ 20) impedisce questa sovrapposizione senza no_unique_address
, per oggetti che non sono banalmente copiabili?
Devo escludere oggetti banalmente copiabili (TC) da quanto sopra, perché per gli oggetti TC, è consentito passare std::memcpy
da un oggetto a un altro, compresi gli oggetti secondari dei membri, e se la memoria fosse sovrapposta si spezzerebbe (perché tutto o parte della memoria poiché il membro adiacente verrebbe sovrascritto) 2 .
1 Calcoliamo l'imbottitura semplicemente come la differenza tra la dimensione della struttura e la dimensione di tutti i suoi componenti, in modo ricorsivo.
2 Questo è il motivo per cui ho definito i costruttori di copie: da rendere blub
e blob
non banalmente copiabili .