#include <vector>
struct S { int x; };
std::vector<S> v;
int main() { v.resize(1000); return v[42].x; }
Czy powyższy program gwarantuje powrót do C++ 14? Czemu?Kontener struktury zawierający typ pierwotny, zero zainicjowany?
#include <vector>
struct S { int x; };
std::vector<S> v;
int main() { v.resize(1000); return v[42].x; }
Czy powyższy program gwarantuje powrót do C++ 14? Czemu?Kontener struktury zawierający typ pierwotny, zero zainicjowany?
Tak, ponieważ std::vector::resize
i podobne metody wykonać inicjalizację wartości domyślnie † co z kolei wartość inicjuje członków agregatów:
Od cppr:
Skutki inicjalizacji wartości to:
[...]
jeśli T jest typem klasy z domyślnym konstruktorem, który nie jest ani podany przez użytkownika, ani usunięty (to znaczy może być klasą z niejawnie zdefiniowanym lub defaulte d domyślny konstruktor), obiekt jest inicjalizowany od zera, a następnie jest inicjowany domyślnie, jeśli ma nietrywialny domyślny konstruktor;
i Zero Initialiation część robi to, czego potrzebujemy:
Jeśli T jest non-union typ klasy, wszystkie klasy bazowe i non-statyczne członkowie danych są zero-zainicjowany, a wszystko wyściółka jest inicjowany do zera bitów. Konstruktory, jeśli istnieją, są ignorowane.
I oczywiście, zero inicjalizacji naszego członka robi słusznie:
Jeśli T jest typem skalarne, wartość początkową obiektu jest integralną stała zerowa wyraźnie konwertowane do T.
† Domyślny program przydzielający nie może używać innej alokacji. Można ich użyć, aby pozostawić takie wartości w jednostce zunifikowanej, patrz pełny artykuł na temat default-insert.
Czy powyższy program gwarantuje powrót do C++ 14? Czemu?
Tak. W [vector.capacity]
void resize(size_type sz);
13 Wpływ: ifsz < size()
, usuwa się ostatniesize() - sz
elementy z sekwencji. W przeciwnym razie dołącza domyślne elementy do sekwencji.
gdzie z [container.requirements.general]
Element
X
jest domyślnych dodaje jeśli jest inicjowana na podstawie zmian ekspresjiallocator_traits<A>::construct(m, p)
gdziep
jest adres z niezainicjowana pamięć dla elementu przydzielonego w ramachX
.
construct
dla std::allocator<T>
robi, z [default.allocator]:
template <class U, class... Args> void construct(U* p, Args&&... args);
Effects:
::new((void *)p) U(std::forward<Args>(args)...)
Tak, to wartości inicjalizacji. Robimy new S()
, a nie new S
, więc członek x
zostanie zinicjalizowany od zera.
Sposoby unikanie to zachowanie (w razie potrzeby) są albo:
construct
: jeden pusty (który wykonałby domyślną inicjalizację) i jeden pobierający Args&&...
.S
, który nie inicjuje.
Możliwy duplikat [Inicjowanie wszystkich podwojeń w klasie do zera] (http://stackoverflow.com/questions/42010793/initializing-all-doubles-in-a-class-to- zero) – SU3