(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 x
ist nicht mehr immer eine Kompilierungszeitkonstante; Der Compiler muss manchmal Code generieren, um einen sizeof
Ausdruck 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 " n
hier definitiv weniger als 1000 sind", deklarieren Sie dies einfach int A[1000]
. Das Ersetzen der 32-Bit-Ganzzahl n
durch 1000
ist 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 n
es keine Kompilierungszeitkonstante gäbe (dh wenn A
sie 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, constexpr
Funktionsbewertung 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).