2013-07-29 14 views
57

è l'assenza diPerché std :: array non ha un costruttore che accetta un valore per l'array da riempire?

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

una svista? Mi sembra molto utile e i contenitori dinamici (come std::vector) hanno un costruttore simile.

Sono pienamente consapevole di

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

ma che non è un costruttore, e la memoria viene azzerato per primo. Cosa succede se voglio tutti i -1 come this guy?

+1

"e la memoria verrà azzerata prima" sei sicuro che sia vero? – tohava

+3

Prima non verrà azzerato, a meno che non lo chieda. –

+1

Oltre all'argomento * aggregato * di tutte le risposte, potrebbe esserci anche un ragionamento più concettuale. Un costruttore di riempimento probabilmente nasconderebbe il fatto che non sta realmente costruendo i singoli elementi. In primo luogo invocherà l'inizializzazione dell'aggregato e * quindi * copierà il valore negli elementi, non può copiare-costruire subito gli elementi (al contrario di, ad esempio, 'std :: vector'). Quindi dato che sarebbe sempre equivalente a 'array(); array.fill(); ', omettendo il costruttore in primo luogo non nasconde questo fatto. –

risposta

45

std::array è, in base alla progettazione, un aggregato, quindi non ha costruttori dichiarati dall'utente.

Come dici tu, potresti usare fill dopo la costruzione di default. Poiché si tratta di un aggregato, la costruzione predefinita non azzererà la memoria, ma la lascerà non inizializzata (se il tipo contenuto è banalmente inizializzabile).

+1

Quindi [questa pagina] (http: // en.cppreference.com/w/cpp/container/array) è sbagliato? Dice esplicitamente che gli elementi dell'array sono inizializzati di default. – rubenvb

+9

L'inizializzazione di default è no-init per i POD e costruttore di default per tutto il resto che credo - a seconda del punto di dichiarazione. – Xeo

+1

@rubenvb: Sì, verranno inizializzati per impostazione predefinita, non inizializzati per valore. Quindi, se sono banalmente inizializzabili, verranno lasciati non inizializzati. –

11

Innanzitutto, non è std::array<T>, è std::array<T,N> dove N è tempo di compilazione espressione integrale costante.

In secondo luogo, std::array viene reso aggregato per progettazione. Quindi non ha nulla che lo rende non aggregato, motivo per cui non ha costruttore ... e distruttore, funzioni virtuali, ecc.

19

Si noti che è possibile simulare in modo efficiente questo tipo di costruttore prendendo vantaggio del fatto che l'array non è inizializzato a zero e ha un costruttore di copia e lo fa.

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

cerchiamo di non gonfiare il sito di chiamata con parametri template non necessari ';-)'. – rubenvb

+4

'char' può essere dedotto, quindi puoi semplicemente scrivere' make_array <20> ('z') 'invece di' make_array <20,char> ('z') ' – Nawaz

+0

@Nawaz oh, ancora meglio. Avrei dovuto chiedere perché non c'è 'make_array' invece' :-) ' – rubenvb

3

È possibile utilizzare std::index sequence per questo:

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 è C++ 14, ma può essere implementato in C++ 11.

Problemi correlati