Inizializzazione di una matrice di membri nell'inizializzatore del costruttore


98
class C 
{
public:
 C() : arr({1,2,3}) //doesn't compile
{}
    /*
    C() : arr{1,2,3} //doesn't compile either
{}
    */
private:
 int arr[3];
};

Credo che il motivo sia che gli array possono essere inizializzati solo con la =sintassi, ovvero:

int arr[3] = {1,3,4};

Domande

  1. Come posso fare quello che voglio fare (cioè inizializzare un array in un costruttore (senza assegnare elementi nel corpo)). È anche possibile?
  2. Lo standard C ++ 03 dice qualcosa di speciale sull'inizializzazione degli aggregati (inclusi gli array) negli inizializzatori ctor? O l'invalidità del codice sopra è un corollario di altre regole?
  3. Gli elenchi di inizializzatori C ++ 0x risolvono il problema?

PS Per favore non menzionare i vettori, boost :: arrays e la loro superiorità rispetto agli array, di cui sono ben consapevole.


Sei anche a conoscenza dell'esistenza di array boost a dimensione fissa, che forniscono costruttori?
Benoît,

2
@ Benoît: lo sono. Ma ho bisogno di sapere sugli array semplici :)
Armen Tsirunyan

Risposte:


55
  1. Come posso fare quello che voglio fare (cioè inizializzare un array in un costruttore (senza assegnare elementi nel corpo)). È anche possibile?

Sì. Utilizza una struttura che contiene un array. Dici di saperlo già, ma poi non capisco la domanda. In questo modo, si fa inizializzare un array nel costruttore, senza incarichi nel corpo. Questo è ciò che boost::arrayfa.

Lo standard C ++ 03 dice qualcosa di speciale sull'inizializzazione degli aggregati (inclusi gli array) negli inizializzatori ctor? O l'invalidità del codice sopra è un corollario di altre regole?

Un inizializzatore di mem utilizza l'inizializzazione diretta. E le regole della clausola 8 vietano questo genere di cose. Non sono esattamente sicuro del seguente caso, ma alcuni compilatori lo consentono.

struct A {
  char foo[6];
  A():foo("hello") { } /* valid? */
};

Vedi questo PR GCC per ulteriori dettagli.

Gli elenchi di inizializzatori C ++ 0x risolvono il problema?

Si lo fanno. Tuttavia la tua sintassi non è valida, credo. Devi usare le parentesi graffe direttamente per attivare l'inizializzazione dell'elenco

struct A {
  int foo[3];
  A():foo{1, 2, 3} { }
  A():foo({1, 2, 3}) { } /* invalid */
};

Mi sono imbattuto in questo quando ho scritto: char * const foo[6];membro della classe. Esso richiede l'inizializzatore compilare in C ++ 11.
JATothrim

33

C ++ 98 non fornisce una sintassi diretta per nient'altro che azzerare (o per elementi non POD, inizializzare il valore) l'array. Per questo devi solo scrivere C(): arr() {}.

Penso che Roger Pate si sbagli sulle presunte limitazioni dell'inizializzazione dell'aggregato C ++ 0x, ma sono troppo pigro per cercarlo o verificarlo, e non importa, vero? MODIFICARE : Roger stava parlando di "C ++ 03", l'ho letto male come "C ++ 0x". Scusa, Roger. ☺

Una soluzione alternativa in C ++ 98 per il codice corrente consiste nel racchiudere l'array in un structe inizializzarlo da una costante statica di quel tipo. I dati devono comunque risiedere da qualche parte. All'inizio può assomigliare a questo:

class C 
{
public:
    C() : arr( arrData ) {}

private:
     struct Arr{ int elem[3]; };
     Arr arr;
     static Arr const arrData;
};

C::Arr const C::arrData = {{1, 2, 3}};

Quali limitazioni ho detto che ha 0x?

@Roger: "inizializzazione aggregata ... non si adatta a un inizializzatore ctor". Basta controllare la bozza C ++ 0x N3126, la sintassi di un inizializzatore di mem , in §12.5.2 / 1, include l'uso di una lista di inizializzazione con parentesi graffe .
Saluti e salute. - Alf

6
Le prime due parole della mia frase sono in C ++ 03, ...

8

Soluzione:

template<class T, size_t N>
struct simple_array { // like std::array in C++0x
   T arr[N];
};


class C : private simple_array<int, 3> 
{
      static simple_array<int, 3> myarr() {
           simple_array<int, 3> arr = {1,2,3};
           return arr;
      }
public:
      C() : simple_array<int, 3>(myarr()) {}
};

3
  1. No Sfortunatamente.
  2. Semplicemente non puoi nel modo che desideri, poiché non è consentito dalla grammatica (più sotto). È possibile utilizzare solo l'inizializzazione simile a quella di un ctor e, come sapete, non è disponibile per inizializzare ogni elemento negli array.
  3. Credo di sì, poiché generalizzano l'inizializzazione su tutta la linea in molti modi utili. Ma non sono sicuro dei dettagli.

In C ++ 03, l'inizializzazione aggregata si applica solo con una sintassi simile a quella riportata di seguito, che deve essere un'istruzione separata e non si adatta a un inizializzatore ctor.

T var = {...};

2

Che ne dite di

...
  C() : arr{ {1,2,3} }
{}
...

?

Compila bene su g ++ 4.8


È questo standard? Puoi citare la clausola pertinente, per favore?
Armen Tsirunyan

2
Non si compila in Visual C ++.
sergiol

-2

Vuoi inizializzare un array di int nel tuo costruttore? Puntalo a un array statico.

class C 
{
public:
    int *cArray;

};

C::C {
    static int c_init[]{1,2,3};
    cArray = c_init;
}

2
Questa è una cattiva idea, perché se cambi quell'array, viene cambiato per tutte le istanze di quella classe.
morty
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.