2013-07-29 14 views
57

jest brakDlaczego std :: array nie ma konstruktora, który pobiera wartość do wypełnienia tablicy?

std::array<T,size>::array(const T& value); 

niedopatrzenie? Wydaje mi się to bardzo przydatne, a dynamiczne pojemniki (takie jak std::vector) mają podobny konstruktor.

Jestem w pełni świadomy

std::array<T,size>::fill(const T& value); 

ale to nie jest konstruktorem, a pamięć zostanie wyzerowany w pierwszej kolejności. Co jeśli chcę, aby wszystkie były -1 jak this guy?

+1

"i pamięć zostanie wyzerowana jako pierwsza" czy jesteś pewien, że to prawda? – tohava

+3

Najpierw nie zostanie wyzerowany, chyba że o to poprosisz. –

+1

Poza * zagregowanym * argumentem ze wszystkich odpowiedzi, może istnieć także bardziej konceptualne uzasadnienie. Konstruktor wypełniania prawdopodobnie ukryłby fakt, że tak naprawdę nie konstruuje on poszczególnych elementów. Najpierw będzie wywoływał zbiorczą inicjalizację i * potem * kopiuje wartość do elementów, nie może kopiować - konstruować elementów od razu (w przeciwieństwie do, powiedzmy 'std :: vector'). Ponieważ zawsze będzie to odpowiednik 'tablica(); array.fill(); ', pominięcie konstruktora w pierwszej kolejności nie ukrywa tego faktu. –

Odpowiedz

45

std::array jest z założenia agregatem, więc nie ma konstruktorów deklarowanych przez użytkownika.

Jak można powiedzieć, można użyć fill po domyślnej konstrukcji. Ponieważ jest to agregat, domyślna konstrukcja nie wyzeruje pamięci, ale pozostawi ją niezainicjowaną (jeśli zawarta czcionka jest trywialnie inicjalizowana).

+1

Tak [ta strona] (http: // en.cppreference.com/w/cpp/container/array) jest nieprawidłowy? Mówi wprost, że elementy tablicy są inicjowane domyślnie. – rubenvb

+9

Domyślna inicjalizacja to nie-init dla POD i domyślny-konstruktor dla wszystkiego, co uważam - w zależności od punktu deklaracji. – Xeo

+1

@rubenvb: Tak, zostaną domyślnie zainicjalizowane, a nie zainicjowane wartością. Więc jeśli są one trywialnie inicjalizowane, to pozostaną niezainicjowane. –

11

Przede wszystkim nie jest to std::array<T>, jest to std::array<T,N>, gdzie N jest ciągłym wyrażeniem integralnym.

Po drugie, std::array jest agregowane według projektu. Nie ma więc niczego, co czyni go nieagregatowym, dlatego nie ma konstruktora ... i destruktora, funkcji wirtualnych itp.

19

Pamiętaj, że możesz efektywnie symulować tego typu konstruktora, biorąc zaletą tego, że macierz nie jest inicjowana zerowo i ma konstruktora kopiowania i nie.

template <size_t N, class T> 
array<T,N> make_array(const T &v) { 
    array<T,N> ret; 
    ret.fill(v); 
    return ret; 
} 

auto a = make_array<20>('z'); 
+0

nie rozchodźmy się po stronie wywołania z niepotrzebnymi parametrami szablonu ';-)'. – rubenvb

+4

'char' można wywnioskować, więc możesz po prostu napisać' make_array <20> ('z') 'zamiast' make_array <20,char> ('z') ' – Nawaz

+0

@Nawaz oh, jeszcze lepiej. Powinienem był zapytać, dlaczego nie ma 'make_array' zamiast' :-) ' – rubenvb

3

Można użyć std::index sequence na to:

namespace detail 
{ 

    template <typename T, std::size_t...Is> 
    std::array<T, sizeof...(Is)> make_array(const T& value, std::index_sequence<Is...>) 
    { 
     return {{(static_cast<void>(Is), value)...}}; 
    } 
} 

template <std::size_t N, typename T> 
std::array<T, N> make_array(const T& value) 
{ 
    return detail::make_array(value, std::make_index_sequence<N>()); 
} 

Demo

std::make_index_sequence jest C++ 14, ale może być realizowany w C++ 11.

Powiązane problemy