Domyślna inicjalizacja std :: array?

104

Czy w przypadku C ++ 11 std::arraymam gwarancję, że składnia std::array<T, N> x;będzie domyślnie inicjowała wszystkie elementy tablicy?

EDYCJA : jeśli nie, czy istnieje składnia, która będzie działać na wszystkich tablicach (w tym tablicach o rozmiarze zerowym), aby zainicjować wszystkie elementy do ich wartości domyślnych?

EDYCJA : w cppreference , domyślny opis konstruktora mówi:

(constructor) (implicitly declared) (public member function)
default-constructs or copy-constructs every element of the array 

więc odpowiedź może brzmieć tak. Ale chciałbym być tego pewien zgodnie ze standardem lub przyszłym standardem.

Vincent
źródło
Nie myśl tak. Jest zadeklarowana domyślnie, więc jest w zasadzie odpowiednikiem T x[N]składni.
Rapptz,

Odpowiedzi:

149

Z definicji inicjalizacja domyślna to inicjalizacja, która ma miejsce, gdy nie określono żadnej innej inicjalizacji; język C ++ gwarantuje, że każdy obiekt, dla którego nie podasz jawnego inicjatora, zostanie domyślnie zainicjowany (C ++ 11 §8.5 / 11). Obejmuje to obiekty typu std::array<T, N>i T[N].

Należy pamiętać, że istnieją typy, dla których domyślna inicjalizacja nie ma wpływu i pozostawia nieokreśloną wartość obiektu: dowolny typ niebędący klasą, nie tablicowy (§8.5 / 6). W konsekwencji, domyślnie zainicjowana tablica obiektów o takich typach będzie miała nieokreśloną wartość, np .:

int plain_int;
int c_style_array[13];
std::array<int, 13> cxx_style_array;

Zarówno tablica w stylu c, jak i std::arraysą wypełnione liczbami całkowitymi o nieokreślonej wartości, tak jak plain_intma nieokreśloną wartość.

Czy istnieje składnia, która będzie działać na wszystkich tablicach (w tym tablicach o rozmiarze zerowym), aby zainicjować wszystkie elementy do ich wartości domyślnych?

Domyślam się, że kiedy mówisz „do ich wartości domyślnej”, naprawdę masz na myśli „zainicjuj wszystkie elementy na T{}”. To nie jest inicjalizacja domyślna , jest to inicjalizacja wartości (8.5 / 7). Możesz łatwo zażądać inicjalizacji wartości w C ++ 11, nadając każdej deklaracji pusty inicjator:

int plain_int{};
int c_style_array[13]{};
std::array<int, 13> cxx_style_array{};

Który z kolei zainicjuje wartość i wartość wszystkich elementów tablicy, w wyniku czego plain_old_intwszystkie elementy członkowskie obu rodzajów tablic zostaną zainicjowane na zero.

Casey
źródło
A co jeśli jest to element klasy: struct X {std :: array <int, 12> kilkanaście; X (): dozen () {} Czy to daje mi dwanaście zer?
gerardw
4
@gerardw Zgodnie ze standardem tak. Uważaj na błędy w MSVC, nie udaje się poprawnie zaimplementować niektórych przypadków inicjalizacji wartości.
Casey,
1
rzeczywiście boost mówi tak i obejdź to za pomocą ich boost::value_initialized łącza, ale uważam, że VC12 (VS2013) ma teraz znacznie lepsze wsparcie.
v.oddou,
1
Żałuję, że komitet nie zmienił standardu na domyślną inicjalizację wartości i obniżoną wartość na żądanie. To znaczy std :: array <int, 12> = {std :: undetermined}; czy coś
Viktor Sehr
Co w praktyce oznacza zainicjowanie czegoś do nieokreślonej wartości? Jaka jest alternatywa?
Andrew
21

Inicjalizacja domyślna to termin ze Standardu, który potencjalnie oznacza brak inicjalizacji, więc prawdopodobnie masz na myśli inicjalizację zerową .

Opis na cppreference.com jest w rzeczywistości nieco mylący. std::arrayjest klasą zagregowaną, a jeśli typ elementu jest prymitywny, to jest to POD: „zwykłe stare dane” z semantyką ściśle dopasowaną do języka C. Niejawnie zdefiniowany konstruktor programu std::array< int, N >jest trywialny i nie robi absolutnie nic.

Składnia taka jak std::array< int, 3 >()lub, std::array< int, 3 > x{}która zapewnia zerowe wartości, nie robi tego przez wywołanie konstruktora. Pobieranie zer jest częścią inicjalizacji wartości , określonej w C ++ 11 §8.5 / 8:

Inicjalizacja wartości obiektu typu T oznacza:

- jeśli T jest typem klasy (prawdopodobnie kwalifikowanym przez cv) bez konstruktora domyślnego dostarczonego przez użytkownika lub usuniętego, to obiekt jest inicjowany przez zero…, a jeśli T ma nietrywialny konstruktor domyślny, obiekt jest inicjalizowany domyślnie;

std::arraynie ma domyślnego konstruktora dostarczonego przez użytkownika, więc jest inicjowany przez zero. Ma domyślnie zdefiniowany konstruktor domyślny, ale jest trywialny, więc nigdy nie jest inicjowany domyślnie. (Ale to nie robi różnicy, ponieważ trywialna inicjalizacja z definicji nie ma wpływu na środowisko wykonawcze).

jeśli nie, to czy istnieje składnia, która będzie działać na wszystkich tablicach (w tym tablicach o rozmiarze zerowym), aby zainicjować wszystkie elementy do ich wartości domyślnych?

Tablice w stylu C i std::arrayoba są agregatami, a sposobem na całkowicie zerową inicjalizację dowolnej agregacji jest składnia = {}. Działa to od C ++ 98. Zauważ, że tablice w stylu C nie mogą mieć zerowego zasięgu, a sizeof (std::array< X, 0 >)to nie jest zero.

Potatoswatter
źródło
6

Zarówno, jak T x[N];i std::array<T, N> x;domyślnie inicjalizuj każdy element tablicy.

Na przykład, jeśli T = std::stringkażdy element będzie pustym ciągiem. Jeśli Tjest to klasa bez domyślnego konstruktora, obie nie będą mogły się skompilować. Jeśli T = intkażdy element będzie miał nieokreśloną wartość (chyba że ta deklaracja znajduje się w zakresie przestrzeni nazw)

Cubbi
źródło
0

Po pierwsze, T x [N] domyślnie inicjalizuje elementy, chociaż domyślna inicjalizacja typu skalarnego T w rzeczywistości nic nie robi. Powyższe dotyczy również std :: array x. Myślę, że potrzebujesz inicjalizacji listy.

Lingxi
źródło