std::array
è di gran lunga superiore agli array C. E anche se voglio interagire con il codice legacy, posso semplicemente usare std::array::data()
. C'è qualche motivo per cui vorrei mai un array della vecchia scuola?
std::array
è di gran lunga superiore agli array C. E anche se voglio interagire con il codice legacy, posso semplicemente usare std::array::data()
. C'è qualche motivo per cui vorrei mai un array della vecchia scuola?
Risposte:
A meno che non mi sia perso qualcosa (non ho seguito troppo da vicino le modifiche più recenti allo standard), la maggior parte degli usi degli array in stile C. std::array
consente l'inizializzazione statica, ma non conterà ancora gli inizializzatori per te. E poiché l'unico vero uso di array in stile C prima std::array
era per tabelle inizializzate staticamente sulla falsariga di:
MyStruct const table[] =
{
{ something1, otherthing1 },
// ...
};
usando le solite funzioni begin
e end
template (adottate in C ++ 11) per iterarle. Senza mai menzionare la dimensione, che il compilatore determina dal numero di inizializzatori.
EDIT: Un'altra cosa che ho dimenticato: i letterali stringa sono ancora array in stile C; cioè con il tipo char[]
. Non penso che qualcuno escluderebbe l'uso di stringhe letterali solo perché abbiamo std::array
.
const char[]
No. Per, uh, per dirla senza mezzi termini. E in 30 caratteri.
Ovviamente, sono necessari array C per l'implementazione std::array
, ma non è davvero un motivo per cui un utente vorrebbe mai array C. Inoltre, no, std::array
non è meno performante di un array C e ha un'opzione per un accesso controllato dai limiti. E infine, è del tutto ragionevole che qualsiasi programma C ++ dipenda dalla libreria Standard - questo è il punto che è Standard - e se non hai accesso a una libreria Standard, il tuo compilatore non è conforme e il la domanda è etichettata "C ++", non "C ++ e quelle cose non-C ++ che perdono metà della specifica perché lo ritengono inappropriato.".
std::array
Tuttavia, avrei seri dubbi su un compilatore che non potrebbe essere implementato in un'implementazione C ++ 11 indipendente.
Sembra usando array multidimensionali è più facile con matrici C rispetto std::array
. Per esempio,
char c_arr[5][6][7];
al contrario di
std::array<std::array<std::array<char, 7>, 6>, 5> cpp_arr;
Anche a causa della proprietà di decadimento automatico degli array C, c_arr[i]
nell'esempio precedente decadrà in un puntatore e devi solo passare le dimensioni rimanenti come altri due parametri. Il punto è che c_arr
non è costoso da copiare. Tuttavia, cpp_arr[i]
sarà molto costoso da copiare.
array
a una funzione senza perdere le dimensioni. E se lo passi a un modello di funzione, quella funzione potrebbe dedurre sia la dimensione che la dimensione di ciascuna dimensione, o solo una delle due. Questo potrebbe essere interessante per le librerie di modelli scientifici che lavorano principalmente su dimensioni arbitrarie.
template <typename T, int M, int N> using array2d = std::array<std::array<T, N>, M>;
dovrebbe risolvere uno qualsiasi di questi problemi.
c_arr
è molto costoso da copiare! Devi fornire il codice per farlo da solo. Il puntatore a cui decade è un equivalente più vicino a un riferimento che a una copia e puoi usarlo std::array
per passare un riferimento se è quello che vuoi.
std::size_t
posto di int
? scusate il pelo nell'uovo, ma questo lo renderebbe universale.
size_t
se vuoi, anche se non riesco a immaginare che ci siano molti scenari in cui sono necessari array con più di 4 miliardi di righe o colonne.
Come ha detto Sumant, gli array multidimensionali sono molto più facili da usare con gli array C incorporati che con std::array
.
Quando annidato, std::array
può diventare molto difficile da leggere e inutilmente prolisso.
Per esempio:
std::array<std::array<int, 3>, 3> arr1;
rispetto a
char c_arr[3][3];
Inoltre, tieni presente che begin()
, end()
e size()
tutti restituiscono valori privi di significato quando annidi std::array
.
Per questi motivi ho creato i miei contenitori di array multidimensionali a dimensione fissa array_2d
e array_3d
. Sono analoghi std::array
ma per array multidimensionali di 2 e 3 dimensioni. Sono più sicuri e non hanno prestazioni peggiori degli array multidimensionali incorporati. Non ho incluso un contenitore per array multidimensionali con dimensioni maggiori di 3 poiché sono rari. In C ++ 0x è possibile creare una versione del modello variadico che supporti un numero arbitrario di dimensioni.
Un esempio della variante bidimensionale:
//Create an array 3 x 5 (Notice the extra pair of braces)
fsma::array_2d <double, 3, 5> my2darr = {{
{ 32.19, 47.29, 31.99, 19.11, 11.19},
{ 11.29, 22.49, 33.47, 17.29, 5.01 },
{ 41.97, 22.09, 9.76, 22.55, 6.22 }
}};
La documentazione completa è disponibile qui:
http://fsma.googlecode.com/files/fsma.html
Puoi scaricare la libreria qui:
arr[x][y]
, non puoi dire se arr
è un array di array, un array di puntatori, un puntatore a un array o un puntatore a un puntatore; tutte le implementazioni sono legittime, a seconda delle esigenze. E probabilmente la maggior parte dei casi d'uso del mondo reale per array multidimensionali richiede che la dimensione sia determinata in fase di esecuzione.
Gli array in stile C disponibili in C ++ sono in realtà molto meno versatili degli array C reali. La differenza è che in C, i tipi di array possono avere dimensioni di runtime . Quanto segue è codice C valido, ma non può essere espresso né con array in stile C C ++ né con i array<>
tipi C ++ :
void foo(int bar) {
double tempArray[bar];
//Do something with the bar elements in tempArray.
}
In C ++, dovresti allocare l'array temporaneo sull'heap:
void foo(int bar) {
double* tempArray = new double[bar];
//Do something with the bar elements behind tempArray.
delete[] tempArray;
}
Questo non può essere ottenuto con std::array<>
, perché bar
non è noto in fase di compilazione, richiede l'uso di array in stile C in C ++ o di std::vector<>
.
Mentre il primo esempio potrebbe essere espresso in modo relativamente facile in C ++ (sebbene richieda new[]
e delete[]
), non è possibile ottenere quanto segue in C ++ senza std::vector<>
:
void smoothImage(int width, int height, int (*pixels)[width]) {
int (*copy)[width] = malloc(height*sizeof(*copy));
memcpy(copy, pixels, height*sizeof(*copy));
for(y = height; y--; ) {
for(x = width; x--; ) {
pixels[y][x] = //compute smoothed value based on data around copy[y][x]
}
}
free(copy);
}
Il punto è che i puntatori agli array di linee int (*)[width]
non possono utilizzare una larghezza di runtime in C ++, il che rende qualsiasi codice di manipolazione delle immagini molto più complicato in C ++ rispetto a C. Una tipica implementazione C ++ dell'esempio di manipolazione delle immagini sarebbe simile a questa:
void smoothImage(int width, int height, int* pixels) {
int* copy = new int[height*width];
memcpy(copy, pixels, height*width*sizeof(*copy));
for(y = height; y--; ) {
for(x = width; x--; ) {
pixels[y*width + x] = //compute smoothed value based on data around copy[y*width + x]
}
}
delete[] copy;
}
Questo codice esegue esattamente gli stessi calcoli del codice C precedente, ma deve eseguire il calcolo dell'indice a mano ovunque vengano utilizzati gli indici . Per il caso 2D, questo è ancora fattibile (anche se offre molte opportunità per sbagliare il calcolo dell'indice). Tuttavia, diventa davvero brutto nel caso 3D.
Mi piace scrivere codice in C ++. Ma ogni volta che ho bisogno di manipolare dati multidimensionali, mi chiedo davvero se devo spostare quella parte del codice in C.
gcc
ad esempio). C11 ha reso opzionali un bel po 'di cose interessanti, e non credo che sia perché vogliono mettere fuori legge la funzione. Tendo a vederlo come un segno che volevano abbassare il livello per scrivere un compilatore conforme agli standard: i VLA sono piuttosto difficili da implementare e molto codice può fare a meno, quindi ha senso per un nuovo compilatore su qualche nuovo piattaforma per non dover implementare immediatamente i VLA.
Forse std::array
non è lento. Ma ho fatto un po 'di benchmarking usando simple store e ho letto da std :: array; Vedere i risultati del benchmark di seguito (su W8.1, VS2013 Update 4):
ARR_SIZE: 100 * 1000
Avrg = Tick / ARR_SIZE;
test_arr_without_init
==>VMem: 5.15Mb
==>PMem: 8.94Mb
==>Tick: 3132
==>Avrg: 0.03132
test_arr_with_init_array_at
==>VMem: 5.16Mb
==>PMem: 8.98Mb
==>Tick: 925
==>Avrg: 0.00925
test_arr_with_array_at
==>VMem: 5.16Mb
==>PMem: 8.97Mb
==>Tick: 769
==>Avrg: 0.00769
test_c_arr_without_init
==>VMem: 5.16Mb
==>PMem: 8.94Mb
==>Tick: 358
==>Avrg: 0.00358
test_c_arr_with_init
==>VMem: 5.16Mb
==>PMem: 8.94Mb
==>Tick: 305
==>Avrg: 0.00305
Secondo i segni negativi, il codice che ho usato è nel pastebin ( link )
Il codice della classe benchmark è qui ;
Non so molto sui benchmarking ... Il mio codice potrebbe essere difettoso
long test_arr_without_init() { return ARR_SIZE; }
void test_arr_without_init() {}
ora. Hai davvero bisogno di saltare attraverso i cerchi per assicurarti che il codice che stai misurando sia il codice che vuoi misurare.
std::array
std::array
sarà meno performante di un array C.
at()
, non è dentro operator[]
, proprio come std::vector
. Non c'è diminuzione delle prestazioni o aumento del codice std::array
, il compilatore è progettato per ottimizzare questo tipo di cose. E, naturalmente, l'aggiunta della funzione selezionata è un eccellente strumento di debug e un grande vantaggio. @Lou Franco: Tutto il codice C ++ può dipendere dalla libreria Standard, questo è un po 'a cosa serve. @Earlz: Se non hai STL disponibile, allora non è C ++, e questa è la fine.
std::array
sia più grande dell'uso equivalente dell'array C.