Warum sind Arrays mit variabler Länge nicht Teil des C ++ - Standards?

326

Ich habe C in den letzten Jahren nicht sehr oft benutzt. Als ich diese Frage heute las , stieß ich auf eine C-Syntax, mit der ich nicht vertraut war.

Anscheinend ist in C99 die folgende Syntax gültig:

void foo(int n) {
    int values[n]; //Declare a variable length array
}

Dies scheint eine ziemlich nützliche Funktion zu sein. Gab es jemals eine Diskussion darüber, es dem C ++ - Standard hinzuzufügen, und wenn ja, warum wurde es weggelassen?

Einige mögliche Gründe:

  • Haarig für Compiler-Anbieter zu implementieren
  • Inkompatibel mit einem anderen Teil des Standards
  • Die Funktionalität kann mit anderen C ++ - Konstrukten emuliert werden

Der C ++ - Standard besagt, dass die Arraygröße ein konstanter Ausdruck sein muss (8.3.4.1).

Ja, natürlich ist mir klar, dass man im Spielzeugbeispiel verwenden könnte std::vector<int> values(m);, aber dies ordnet Speicher vom Heap und nicht vom Stapel zu. Und wenn ich ein mehrdimensionales Array möchte wie:

void foo(int x, int y, int z) {
    int values[x][y][z]; // Declare a variable length array
}

Die vectorVersion wird ziemlich ungeschickt:

void foo(int x, int y, int z) {
    vector< vector< vector<int> > > values( /* Really painful expression here. */);
}

Die Slices, Zeilen und Spalten werden möglicherweise auch über den gesamten Speicher verteilt.

Wenn man sich die Diskussion anschaut comp.std.c++, ist klar, dass diese Frage mit einigen sehr schwergewichtigen Namen auf beiden Seiten des Arguments ziemlich kontrovers ist. Es ist sicherlich nicht offensichtlich, dass a std::vectorimmer eine bessere Lösung ist.

Andreas Brinck
quelle
3
Warum muss es aus Neugier auf dem Stapel zugewiesen werden? Haben Sie solche Angst vor Problemen mit der Heap-Zuweisungsleistung?
Dimitri C.
32
@ Dimitri Nicht wirklich, aber es ist nicht zu leugnen, dass die Stapelzuweisung schneller ist als die Heapzuweisung. In einigen Fällen kann dies von Bedeutung sein.
Andreas Brinck
11
Der Hauptvorteil von Arrays mit variabler Länge besteht darin, dass alle Daten nahe beieinander liegen. Wenn Sie also durch dieses Array iterieren, lesen und schreiben Sie Bytes nebeneinander. Ihre Daten werden in den Cache abgerufen und die CPU kann daran arbeiten, ohne die Bytes abzurufen und an den / vom Speicher zu senden.
Calmarius
4
Arrays mit variabler Länge können auch verwendet werden, um Präprozessorkonstanten durch statische Konstantenvariablen zu ersetzen. Auch in C haben Sie keine weiteren Optionen für VLA, und manchmal ist es erforderlich, tragbaren C / C ++ - Code zu schreiben (kompatibel mit beiden Compilern).
Yury
2
Nebenbei scheint es, dass clang ++ VLAs erlaubt.
user3426763

Antworten:

204

Vor kurzem gab es eine Diskussion darüber, die im Usenet gestartet wurde: Warum keine VLAs in C ++ 0x .

Ich stimme den Leuten zu, die der Meinung zu sein scheinen, dass es nicht gut ist, ein potenziell großes Array auf dem Stapel zu erstellen, für das normalerweise nur wenig Speicherplatz verfügbar ist. Das Argument ist, wenn Sie die Größe vorher kennen, können Sie ein statisches Array verwenden. Und wenn Sie die Größe vorher nicht kennen, schreiben Sie unsicheren Code.

C99-VLAs könnten einen kleinen Vorteil darin haben, kleine Arrays erstellen zu können, ohne Speicherplatz zu verschwenden oder Konstruktoren für nicht verwendete Elemente aufzurufen, aber sie führen zu ziemlich großen Änderungen am Typsystem (Sie müssen in der Lage sein, Typen abhängig von den Laufzeitwerten anzugeben - dies existiert in aktuellem C ++ noch nicht, außer für newOperator-Typ-Spezifizierer, aber sie werden speziell behandelt, damit die Laufzeit nicht dem Bereich des newOperators entgeht.

Sie können verwenden std::vector, aber es ist nicht ganz dasselbe, da es dynamischen Speicher verwendet, und es ist nicht gerade einfach, den eigenen Stapelzuweiser zu verwenden (auch die Ausrichtung ist ein Problem). Es löst auch nicht das gleiche Problem, da ein Vektor ein Container mit veränderbarer Größe ist, während VLAs eine feste Größe haben. Mit dem Vorschlag für ein dynamisches C ++ - Array soll eine bibliotheksbasierte Lösung als Alternative zu einer sprachbasierten VLA eingeführt werden. Soweit ich weiß, wird es jedoch nicht Teil von C ++ 0x sein.

Johannes Schaub - litb
quelle
22
+1 und akzeptiert. Ein Kommentar, ich denke, das Sicherheitsargument ist ein bisschen schwach, da es so viele andere Möglichkeiten gibt, Stapelüberläufe zu verursachen. Das Sicherheitsargument könnte verwendet werden, um die Position zu unterstützen, dass Sie niemals eine Rekursion verwenden sollten und dass Sie alle Objekte aus dem Heap zuweisen sollten .
Andreas Brinck
17
Sie sagen also, weil es andere Möglichkeiten gibt, Stapelüberläufe zu verursachen, könnten wir genauso gut mehr davon fördern?
Jalf
3
@ Andrew, stimmte über die Schwäche. Für die Rekursion ist jedoch eine große Anzahl von Aufrufen erforderlich, bis der Stapel aufgebraucht ist. Wenn dies der Fall sein kann, verwenden die Benutzer die Iteration. Wie einige Leute im Usenet-Thread sagen, ist dies jedoch nicht in allen Fällen ein Argument gegen VLAs, da Sie manchmal definitiv eine Obergrenze kennen. Aber in diesen Fällen kann aus meiner Sicht ein statisches Array ebenso ausreichend sein, da es sowieso nicht viel Platz verschwenden würde (wenn dies der Fall wäre , müssten Sie tatsächlich fragen, ob der Stapelbereich wieder groß genug ist).
Johannes Schaub - litb
10
Schauen Sie sich auch die Antwort von Matt Austern in diesem Thread an: Die Sprachspezifikation von VLAs wäre für C ++ aufgrund der strengeren Typübereinstimmungen in C ++ wahrscheinlich erheblich komplexer (Beispiel: C ermöglicht die Zuweisung von a T(*)[]zu a T(*)[N]- in C ++ ist dies nicht zulässig, da C ++ weiß nichts über "Typkompatibilität" - es erfordert genaue Übereinstimmungen), Typparameter, Ausnahmen, Konstruktoren und Destruktoren und so. Ich bin mir nicht sicher, ob sich die Vorteile von VLAs wirklich auszahlen würden. Aber dann habe ich im wirklichen Leben noch nie VLAs verwendet, daher kenne ich wahrscheinlich keine guten Anwendungsfälle für sie.
Johannes Schaub - litb
1
@AHelps: Vielleicht wäre das für einen Typ am besten, der sich etwas verhält, vectoraber ein festes LIFO-Verwendungsmuster erfordert und einen oder mehrere statisch zugewiesene Puffer pro Thread verwaltet, die im Allgemeinen entsprechend der größten Gesamtzuordnung des Threads dimensioniert sind jemals verwendet, aber die könnte explizit gekürzt werden. Eine normale "Zuordnung" würde im allgemeinen Fall nichts weiter als eine Zeigerkopie, eine Zeiger-von-Zeiger-Subtraktion, einen ganzzahligen Vergleich und eine Zeigeraddition erfordern; Die Aufhebung der Zuordnung würde lediglich eine Zeigerkopie erfordern. Nicht viel langsamer als ein VLA.
Supercat
216

(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).

Quuxpluson
quelle
15
Ich bin damit einverstanden, dass VLAs einfach falsch waren. Die viel weiter verbreiteten und weitaus nützlicheren alloca()sollten stattdessen in C99 standardisiert worden sein. VLAs sind das, was passiert, wenn ein Standardkomitee vor Implementierungen herausspringt und nicht umgekehrt.
MadScientist
10
Das variabel modifizierte Typsystem ist eine großartige Ergänzung, IMO, und keiner Ihrer Stichpunkte verstößt gegen den gesunden Menschenverstand. (1) Der C-Standard unterscheidet nicht zwischen "Kompilierungszeit" und "Laufzeit", so dass dies kein Problem darstellt. (2) Das *ist optional, Sie können (und sollten) schreiben int A[][n]; (3) Sie können das Typsystem verwenden, ohne tatsächlich VLAs zu deklarieren. Beispielsweise kann eine Funktion ein Array von variabel modifiziertem Typ akzeptieren und mit Nicht-VLA-2D-Arrays mit unterschiedlichen Abmessungen aufgerufen werden. Sie machen jedoch im letzten Teil Ihres Beitrags gültige Punkte.
MM
3
"Das Deklarieren eines VLA bedeutet, einen beliebig großen Teil Ihres Stapels zu zerlegen. Dies ist ein garantierter Stapelüberlauf und Absturz. (Jedes Mal, wenn Sie int A [n] deklarieren, behaupten Sie implizit, dass Sie 2 GB Stapel übrig haben", ist empirisch false. Ich habe gerade ein VLA-Programm mit einem Stapel von weit weniger als 2 GB ohne Stapelüberlauf ausgeführt.
Jeff
3
@ Jeff: Was war der Maximalwert nin Ihrem Testfall und wie groß war Ihr Stapel? Ich schlage vor, Sie versuchen, einen Wert einzugeben, der nmindestens so groß ist wie die Größe Ihres Stapels. (Und wenn es für den Benutzer keine Möglichkeit gibt, den Wert von nin Ihrem Programm zu steuern , dann schlage ich vor, dass Sie den Maximalwert von ndirekt in die Deklaration übertragen: deklarieren int A[1000]oder was auch immer Sie benötigen. VLAs sind nur notwendig und nur gefährlich. wenn der Maximalwert von nnicht durch eine kleine Kompilierungszeitkonstante begrenzt ist.)
Quuxplusone
2
Da alloca () unter Verwendung solcher Eigenheiten implementiert werden kann, ist es per Definition wahr, dass alloca () auf jeder Plattform als Compiler-Standardfunktion implementiert werden kann. Es gibt keinen Grund, warum der Compiler die erste Instanz von alloca () nicht erkennen und nicht festlegen konnte, dass die Arten von Markierungen und Releases in den Code eingebettet werden, und es gibt keinen Grund, warum ein Compiler alloca () nicht mithilfe des Heaps implementieren kann, wenn Mit dem Stack geht das nicht. Was hart / nicht portabel ist, ist, dass alloca () auf einem C-Compiler implementiert ist , so dass es auf einer Vielzahl von Compilern und Betriebssystemen funktioniert.
MadScientist
26

Sie können jederzeit alloca () verwenden, um zur Laufzeit Speicher auf dem Stapel zuzuweisen, wenn Sie dies wünschen:

void foo (int n)
{
    int *values = (int *)alloca(sizeof(int) * n);
}

Die Zuweisung auf dem Stapel bedeutet, dass er automatisch freigegeben wird, wenn der Stapel abgewickelt wird.

Kurzer Hinweis: Wie in der Mac OS X-Manpage für alloca (3) erwähnt, "ist die alloca () -Funktion maschinen- und compilerabhängig; ihre Verwendung wird nicht empfohlen." Nur damit du es weißt.

PfhorSlayer
quelle
4
Der Gültigkeitsbereich für alloca () ist auch die gesamte Funktion, nicht nur der Codeblock, der die Variable enthält. Wenn Sie es also innerhalb einer Schleife verwenden, wird der Stapel kontinuierlich vergrößert. Ein VLA hat dieses Problem nicht.
Sashoalm
3
VLAs mit dem Umfang des umschließenden Blocks bedeuten jedoch, dass sie mit dem Umfang der gesamten Funktion wesentlich weniger nützlich sind als alloca (). Bedenken Sie: if (!p) { p = alloca(strlen(foo)+1); strcpy(p, foo); } Dies ist mit VLAs nicht möglich, gerade wegen ihres Blockumfangs.
MadScientist
1
Das beantwortet nicht die Warum- Frage von OP . Darüber hinaus ist dies eine Cähnliche Lösung und nicht wirklich C++.
Adrian W
13

In meiner eigenen Arbeit habe ich festgestellt, dass es mir jedes Mal, wenn ich etwas wie automatische Arrays mit variabler Länge oder alloca () wollte, egal war, dass sich der Speicher physisch auf dem CPU-Stapel befand, nur dass er von dort stammte Einige Stapelzuweiser, die keine langsamen Fahrten zum allgemeinen Haufen verursachten. Ich habe also ein Pro-Thread-Objekt, das Speicher besitzt, aus dem Puffer mit variabler Größe gepusht / eingeblendet werden können. Auf einigen Plattformen lasse ich dies über mmu wachsen. Andere Plattformen haben eine feste Größe (normalerweise wird dies auch von einem CPU-Stapel mit fester Größe begleitet, da keine mmu vorhanden sind). Eine Plattform, mit der ich arbeite (eine Handheld-Spielekonsole), hat ohnehin einen wertvollen kleinen CPU-Stapel, da sie sich in einem knappen, schnellen Speicher befindet.

Ich sage nicht, dass es niemals erforderlich ist, Puffer variabler Größe auf den CPU-Stapel zu verschieben. Ehrlich gesagt war ich überrascht, als ich herausfand, dass dies kein Standard war, da das Konzept sicherlich gut genug in die Sprache passt. Für mich sind die Anforderungen "variable Größe" und "muss sich physisch auf dem CPU-Stapel befinden" jedoch nie zusammengekommen. Es ging um Geschwindigkeit, also habe ich meinen eigenen "parallelen Stapel für Datenpuffer" erstellt.

Eric
quelle
12

Es gibt Situationen, in denen das Zuweisen von Heapspeicher im Vergleich zu den ausgeführten Vorgängen sehr teuer ist. Ein Beispiel ist die Matrixmathematik. Wenn Sie mit kleinen Matrizen arbeiten, z. B. 5 bis 10 Elemente, und viel rechnen, ist der Malloc-Overhead sehr bedeutend. Gleichzeitig erscheint es sehr verschwenderisch und unflexibel, die Größe zu einer Kompilierungszeitkonstante zu machen.

Ich denke, dass C ++ an sich so unsicher ist, dass das Argument, "nicht mehr unsichere Funktionen hinzuzufügen", nicht sehr stark ist. Auf der anderen Seite, da C ++ wohl die laufzeiteffizienteste Programmiersprachenfunktion ist, die es immer nützlicher macht: Leute, die leistungskritische Programme schreiben, werden C ++ in großem Umfang verwenden und sie benötigen so viel Leistung wie möglich. Das Verschieben von Sachen vom Haufen zum Stapel ist eine solche Möglichkeit. Das Reduzieren der Anzahl von Heap-Blöcken ist eine andere. Das Zulassen von VLAs als Objektmitglieder wäre eine Möglichkeit, dies zu erreichen. Ich arbeite an einem solchen Vorschlag. Die Implementierung ist zwar etwas kompliziert, scheint aber durchaus machbar.

Bengt Gustafsson
quelle
12

Scheint, dass es in C ++ 14 verfügbar sein wird:

https://en.wikipedia.org/wiki/C%2B%2B14#Runtime-sized_one_dimensional_arrays

Update: Es hat es nicht in C ++ 14 geschafft.

Viktor Sehr
quelle
interessant. Herb Sutter diskutiert es hier unter Dynamic Arrays : isocpp.org/blog/2013/04/trip-report-iso-c-spring-2013-meeting (dies ist die Referenz für die Wikipedia-Informationen)
Standard
1
"Arrays und Dynarrays in Laufzeitgröße wurden in die technische Spezifikation für Array-Erweiterungen verschoben", schrieb 78.86.152.103 am 18. Januar 2014 auf Wikipedia: en.wikipedia.org/w/…
strager
10
Wikipedia ist keine normative Referenz :) Dieser Vorschlag hat es nicht in C ++ 14 geschafft.
MM
2
@ViktorSehr: Wie ist der Status dieses Wrt C ++ 17?
Einpoklum
@einpoklum Keine Ahnung, benutze boost :: container :: static_vector
Viktor Sehr
7

Dies wurde für die Aufnahme in C ++ / 1x in Betracht gezogen, wurde jedoch gestrichen (dies ist eine Korrektur zu dem, was ich zuvor gesagt habe).

In C ++ wäre es sowieso weniger nützlich, da wir std::vectordiese Rolle bereits ausfüllen müssen.

philsquared
quelle
42
Nein, std :: vector weist dem Stapel keine Daten zu. :)
Kos
7
"der Stapel" ist ein Implementierungsdetail; Der Compiler kann von überall Speicher zuweisen, solange die Garantien für die Objektlebensdauer erfüllt sind.
MM
1
@MM: Fair genug, aber in der Praxis können wir immer noch nicht verwenden, std::vectoranstatt beispielsweise alloca().
Einpoklum
@einpoklum in Bezug auf die korrekte Ausgabe für Ihr Programm können Sie. Leistung ist ein Problem der Implementierungsqualität
MM
1
Die @ MM-Implementierungsqualität ist nicht portierbar. und wenn Sie keine Leistung benötigen, verwenden Sie C ++ überhaupt nicht
Kumpel
3

Verwenden Sie dazu std :: vector. Zum Beispiel:

std::vector<int> values;
values.resize(n);

Der Speicher wird auf dem Heap zugewiesen, dies hat jedoch nur einen geringen Leistungsnachteil. Darüber hinaus ist es ratsam, dem Stapel keine großen Datenblöcke zuzuweisen, da seine Größe eher begrenzt ist.

Dimitri C.
quelle
4
Eine Hauptanwendung für Arrays variabler Länge ist die Auswertung von Polynomen beliebigen Grades. In diesem Fall bedeutet Ihr "kleiner Leistungsnachteil" "der Code läuft in typischen Fällen fünfmal langsamer". Das ist nicht klein.
AHelps
1
Warum benutzt du nicht einfach std::vector<int> values(n);? Durch die Verwendung resizenach dem Bau verbieten Sie unbewegliche Typen.
LF
1

C99 erlaubt VLA. Und es gibt einige Einschränkungen für die Deklaration von VLA. Einzelheiten finden Sie in 6.7.5.2 des Standards. C ++ verbietet VLA. Aber g ++ erlaubt es.

Jingguo Yao
quelle
Können Sie einen Link zu dem Standardabsatz bereitstellen, auf den Sie zeigen?
Vincent
0

Arrays wie dieses sind Teil von C99, aber nicht Teil von Standard-C ++. Wie andere gesagt haben, ist ein Vektor immer eine viel bessere Lösung, weshalb Arrays mit variabler Größe wahrscheinlich nicht im C ++ - Standard (oder im vorgeschlagenen C ++ 0x-Standard) enthalten sind.

Übrigens, für Fragen zum "Warum" des C ++ - Standards ist die moderierte Usenet-Newsgroup comp.std.c ++ der richtige Ort.


quelle
6
-1 Vektor ist nicht immer besser. Oft ja. Immer nein. Wenn Sie nur ein kleines Array benötigen, sich auf einer Plattform befinden, auf der der Heap-Speicherplatz langsam ist und die Implementierung des Vektors in Ihrer Bibliothek Heap-Speicherplatz verwendet, ist diese Funktion möglicherweise besser, wenn sie vorhanden ist.
Patrick M
-1

Wenn Sie den Wert zur Kompilierungszeit kennen, können Sie Folgendes tun:

template <int X>
void foo(void)
{
   int values[X];

}

Bearbeiten: Sie können einen Vektor erstellen, der einen Stapelzuweiser (Alloca) verwendet, da der Allokator ein Vorlagenparameter ist.

Edouard A.
quelle
18
Wenn Sie den Wert zur Kompilierungszeit kennen, benötigen Sie überhaupt keine Vorlage. Verwenden Sie X einfach direkt in Ihrer Nicht-Vorlagenfunktion.
Rob Kennedy
3
Manchmal weiß der Anrufer beim Kompilieren Bescheid und der Angerufene nicht. Dafür sind Vorlagen gut. Natürlich kennt im Allgemeinen niemand X bis zur Laufzeit.
Qwertie
Sie können alloca nicht in einem STL-Allocator verwenden. Der zugewiesene Speicher von alloca wird freigegeben, wenn der Stapelrahmen zerstört wird. Dann kehrt die Methode zurück, die den Speicher zuordnen soll.
Oliver
-5

Ich habe eine Lösung, die tatsächlich für mich funktioniert hat. Ich wollte wegen der Fragmentierung einer Routine, die viele Male ausgeführt werden musste, keinen Speicher zuweisen. Die Antwort ist äußerst gefährlich. Verwenden Sie sie daher auf eigenes Risiko. Sie nutzt jedoch die Montage, um Platz auf dem Stapel zu reservieren. In meinem folgenden Beispiel wird ein Zeichenarray verwendet (offensichtlich würde eine Variable anderer Größe mehr Speicher benötigen).

void varTest(int iSz)
{
    char *varArray;
    __asm {
        sub esp, iSz       // Create space on the stack for the variable array here
        mov varArray, esp  // save the end of it to our pointer
    }

    // Use the array called varArray here...  

    __asm {
        add esp, iSz       // Variable array is no longer accessible after this point
    } 
}

Die Gefahren hier sind vielfältig, aber ich werde einige erklären: 1. Eine Änderung der Variablengröße auf halbem Weg würde die Stapelposition zerstören. 2. Ein Überschreiten der Array-Grenzen würde andere Variablen und möglichen Code zerstören. 3. Dies funktioniert nicht in einem 64-Bit build ... brauche eine andere Assembly für diese (aber ein Makro könnte dieses Problem lösen). 4. Compilerspezifisch (kann Probleme beim Wechseln zwischen Compilern haben). Ich habe es nicht versucht, also weiß ich es wirklich nicht.

Alan
quelle
... und wenn Sie dies selbst rollen möchten, verwenden Sie vielleicht eine RAII-Klasse?
Einpoklum
Sie könnten einfach boost :: container :: static_vector du verwenden.
Viktor Sehr
Dies hat keine Entsprechungen für andere Compiler, die mehr Raw-Assembly als MSVC haben. VC wird das wahrscheinlich verstehen espund seine Zugriffe auf den Stapel anpassen, aber in z. B. GCC werden Sie es einfach vollständig brechen - zumindest wenn Sie Optimierungen verwenden und -fomit-frame-pointerinsbesondere.
Ruslan