Rozważ następujące trzy struct
s:
class blub {
int i;
char c;
blub(const blub&) {}
};
class blob {
char s;
blob(const blob&) {}
};
struct bla {
blub b0;
blob b1;
};
Na typowych platformach, na których int
są 4 bajty, rozmiary, wyrównania i całkowite wypełnienie 1 są następujące:
struct size alignment padding
-------- ------ ----------- ---------
blub 8 4 3
blob 1 1 0
bla 12 4 6
Przechowywanie elementów blub
i blob
elementów nie zachodzi na siebie , mimo że rozmiar 1 blob
mógłby w zasadzie „pasować” do wypełnienia blub
.
C ++ 20 wprowadza no_unique_address
atrybut, który pozwala sąsiednim pustym członkom na dzielenie tego samego adresu. Pozwala to również wyraźnie na opisany powyżej scenariusz użycia wypełnienia jednego elementu do przechowywania innego. Z preferencji (moje podkreślenie):
Wskazuje, że ten członek danych nie musi mieć adresu odrębnego od wszystkich innych niestatycznych członków danych swojej klasy. Oznacza to, że jeśli element członkowski ma pusty typ (np. Bezstanowy alokator), kompilator może go zoptymalizować, aby nie zajmował miejsca, tak jakby był pustą bazą. Jeśli element członkowski nie jest pusty, wszelkie wypełnienia ogona mogą zostać ponownie wykorzystane do przechowywania innych elementów danych.
Rzeczywiście, jeśli użyjemy tego atrybutu blub b0
, wielkość bla
kropli spadnie do 8
, więc blob
rzeczywiście jest on przechowywany w blub
postaci widocznej na godbolt .
Wreszcie dochodzimy do mojego pytania:
Jaki tekst w standardach (od C ++ 11 do C ++ 20) zapobiega temu nakładaniu się no_unique_address
, w przypadku obiektów, których nie można w prosty sposób skopiować?
Muszę wykluczyć z powyższego obiekty trywialnie kopiowalne (TC), ponieważ w przypadku obiektów TC dozwolone jest przechodzenie std::memcpy
z jednego obiektu do drugiego, w tym podobiektów składowych, a jeśli magazyn byłby nałożony, to by się zepsuło (ponieważ całość lub część magazynu ponieważ sąsiedni członek zostanie zastąpiony) 2 .
1 Obliczamy wypełnienie po prostu rekurencyjnie jako różnicę między rozmiarem struktury a rozmiarem wszystkich jej elementów składowych.
2 Jest to dlaczego mam konstruktory kopia zdefiniowane: zrobić blub
i blob
nie trywialnie copyable .