(Hintergrund: Ich habe einige Erfahrung mit der Implementierung von C- und C ++ - Compilern.)
Arrays mit variabler Länge in C99 waren im Grunde ein Fehltritt. Um VLAs zu unterstützen, musste C99 dem gesunden Menschenverstand folgende Zugeständnisse machen:
sizeof xist nicht mehr immer eine Kompilierungszeitkonstante; Der Compiler muss manchmal Code generieren, um einen sizeofAusdruck zur Laufzeit auszuwerten .
Das Zulassen von zweidimensionalen VLAs ( int A[x][y]) erforderte eine neue Syntax zum Deklarieren von Funktionen, die 2D-VLAs als Parameter verwenden : void foo(int n, int A[][*]).
In der C ++ - Welt weniger wichtig, aber für Cs Zielgruppe von Programmierern für eingebettete Systeme äußerst wichtig, bedeutet das Deklarieren einer VLA, einen beliebig großen Teil Ihres Stapels zu zerlegen . Dies ist ein garantierter Stapelüberlauf und Absturz. (Jedes Mal int A[n], wenn Sie deklarieren , behaupten Sie implizit, dass Sie 2 GB Stack übrig haben. Wenn Sie wissen, dass " nhier definitiv weniger als 1000 sind", deklarieren Sie dies einfach int A[1000]. Das Ersetzen der 32-Bit-Ganzzahl ndurch 1000ist eine Zulassung dass Sie keine Ahnung haben, wie sich Ihr Programm verhalten soll.)
Okay, lassen Sie uns jetzt über C ++ sprechen. In C ++ haben wir die gleiche starke Unterscheidung zwischen "Typsystem" und "Wertesystem" wie in C89 ... aber wir haben wirklich begonnen, uns auf eine Weise darauf zu verlassen, die C nicht hat. Zum Beispiel:
template<typename T> struct S { ... };
int A[n];
S<decltype(A)> s; // equivalently, S<int[n]> s;
Wenn nes keine Kompilierungszeitkonstante gäbe (dh wenn Asie vom variabel modifizierten Typ wäre), was um alles in der Welt wäre dann der Typ S? Würde S‚s Art auch nur zur Laufzeit ermittelt?
Was ist damit:
template<typename T> bool myfunc(T& t1, T& t2) { ... };
int A1[n1], A2[n2];
myfunc(A1, A2);
Der Compiler muss Code für eine Instanziierung von generieren myfunc. Wie sollte dieser Code aussehen? Wie können wir diesen Code statisch generieren, wenn wir den Typ nicht kennen?A1 beim Kompilieren ?
Schlimmer noch, was ist, wenn sich zur Laufzeit herausstellt n1 != n2, dass !std::is_same<decltype(A1), decltype(A2)>()? In diesem Fall sollte der Aufruf von myfunc nicht einmal kompiliert werden , da der Abzug des Vorlagentyps fehlschlagen sollte! Wie könnten wir dieses Verhalten möglicherweise zur Laufzeit emulieren?
Grundsätzlich bewegt sich C ++ in die Richtung, immer mehr Entscheidungen in die Kompilierungszeit zu verschieben : Generierung von Vorlagencode, constexprFunktionsbewertung usw. In der Zwischenzeit war C99 damit beschäftigt, traditionell Entscheidungen zur Kompilierungszeit (z. B. sizeof) in die Laufzeit zu verschieben . Ist es in diesem Sinne überhaupt sinnvoll, Anstrengungen zu unternehmen , um VLAs im C99-Stil in C ++ zu integrieren?
Wie jeder andere Antwortende bereits betont hat, bietet C ++ viele Heap-Zuweisungsmechanismen ( std::unique_ptr<int[]> A = new int[n];oder std::vector<int> A(n);die offensichtlichen), wenn Sie wirklich die Idee vermitteln möchten: "Ich habe keine Ahnung, wie viel RAM ich möglicherweise benötige." Und C ++ bietet ein geschicktes Modell für die Ausnahmebehandlung, um die unvermeidliche Situation zu bewältigen, dass die benötigte RAM-Größe größer ist als die vorhandene RAM-Größe. Aber hoffentlich gibt Ihnen diese Antwort eine gute Vorstellung davon, warum VLAs im C99-Stil nicht gut zu C ++ passen - und nicht einmal wirklich gut zu C99. ;)
Weitere Informationen zu diesem Thema finden Sie in N3810 "Alternativen für Array-Erweiterungen" , Bjarne Stroustrups Artikel über VLAs vom Oktober 2013. Bjarnes POV unterscheidet sich sehr von meinem; N3810 konzentriert sich mehr darauf, eine gute C ++ - Ish- Syntax für die Dinge zu finden und die Verwendung von Raw-Arrays in C ++ zu unterbinden, während ich mich mehr auf die Auswirkungen auf die Metaprogrammierung und das Typensystem konzentrierte. Ich weiß nicht, ob er die Auswirkungen der Metaprogrammierung / des Typensystems für gelöst, lösbar oder nur uninteressant hält.
Ein guter Blog-Beitrag, der viele dieser Punkte trifft, ist "Legitime Verwendung von Arrays mit variabler Länge" (Chris Wellons, 27.10.2019).