(Background: ho una certa esperienza nell'implementazione di compilatori C e C ++.)
Le matrici a lunghezza variabile in C99 erano sostanzialmente un passo falso. Per supportare i VLA, C99 doveva fare le seguenti concessioni al buon senso:
sizeof x
non è più sempre una costante di compilazione; il compilatore deve talvolta generare codice per valutare sizeof
un'espressione in fase di esecuzione.
Permettendo VLA bidimensionali ( int A[x][y]
) necessaria una nuova sintassi per le funzioni che accettano 2D VLA come parametri dichiara: void foo(int n, int A[][*])
.
Ancora meno importante nel mondo C ++, ma estremamente importante per il pubblico target di C di programmatori di sistemi embedded, dichiarare un VLA significa tagliare un pezzo arbitrariamente grande del proprio stack. Questo è uno stack overflow e crash garantito . (Ogni volta che si dichiara int A[n]
, si sta implicitamente affermando che avete 2GB di stack di riserva. Dopo tutto, se si sa " n
è sicuramente inferiore a 1000 qui", quindi si sarebbe solo dichiarare int A[1000]
. Sostituendo il numero intero a 32 bit n
per 1000
è un'ammissione che non hai idea di quale dovrebbe essere il comportamento del tuo programma.)
Bene, passiamo ora a parlare di C ++. In C ++, abbiamo la stessa forte distinzione tra "sistema di tipo" e "sistema di valori" che fa C89 ... ma abbiamo davvero iniziato a fare affidamento su di esso in modi che C non ha. Per esempio:
template<typename T> struct S { ... };
int A[n];
S<decltype(A)> s; // equivalently, S<int[n]> s;
Se n
non fosse una costante di compilazione (cioè se A
fosse di tipo variamente modificato), quale sarebbe il tipo di S
? Sarebbe S
's tipo anche essere determinata solo in fase di esecuzione?
Che dire di questo:
template<typename T> bool myfunc(T& t1, T& t2) { ... };
int A1[n1], A2[n2];
myfunc(A1, A2);
Il compilatore deve generare il codice per alcune istanze di myfunc
. Come dovrebbe essere quel codice? Come possiamo generare staticamente quel codice, se non conosciamo il tipo di A1
al momento della compilazione?
Peggio ancora, cosa succede se si scopre in fase di esecuzione che n1 != n2
, in modo che !std::is_same<decltype(A1), decltype(A2)>()
? In tal caso, la chiamata a myfunc
non dovrebbe nemmeno essere compilata , perché la deduzione del tipo di modello non dovrebbe riuscire! Come potremmo eventualmente emulare quel comportamento in fase di esecuzione?
Fondamentalmente, C ++ si sta muovendo nella direzione di spingere sempre più decisioni in fase di compilazione : generazione di codice modello, constexpr
valutazione delle funzioni e così via. Nel frattempo, C99 era impegnato a spingere le decisioni tradizionalmente in fase di compilazione (ad es. sizeof
) Nel runtime . Con questo in mente, ha davvero senso spendere qualche sforzo nel tentativo di integrare i VLA in stile C99 in C ++?
Come ogni altro risponditore ha già sottolineato, C ++ fornisce molti meccanismi di allocazione dell'heap ( std::unique_ptr<int[]> A = new int[n];
o std::vector<int> A(n);
essendo quelli ovvi) quando si vuole davvero trasmettere l'idea "Non ho idea di quanta RAM potrei avere bisogno". E C ++ fornisce un elegante modello di gestione delle eccezioni per affrontare l'inevitabile situazione in cui la quantità di RAM necessaria è maggiore della quantità di RAM che hai. Ma spero che questa risposta ti dia una buona idea del perché i VLA in stile C99 non si adattano bene al C ++ e non si adattano nemmeno al C99. ;)
Per ulteriori informazioni sull'argomento, vedere N3810 "Alternative per estensioni di array" , articolo di Bjarne Stroustrup dell'ottobre 2013 sui VLA. Il POV di Bjarne è molto diverso dal mio; N3810 si concentra maggiormente sulla ricerca di una buona sintassi ish C ++ per le cose e sullo scoraggiamento dell'uso di array grezzi in C ++, mentre mi sono concentrato maggiormente sulle implicazioni per la metaprogrammazione e il sistema dei tipi. Non so se considera risolte, risolvibili o semplicemente poco interessanti le implicazioni relative alla metaprogrammazione / tipi di sistema.
Un buon post sul blog che colpisce molti di questi stessi punti è "Uso legittimo di array a lunghezza variabile" (Chris Wellons, 27-10-2019).