Dlaczego tablice o zmiennej długości nie są częścią standardu C ++?

326

Nie używałem C bardzo często przez ostatnie kilka lat. Kiedy dzisiaj przeczytałem to pytanie , natknąłem się na składnię C, której nie znałem.

Najwyraźniej w C99 obowiązuje następująca składnia:

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

To wydaje się dość przydatną funkcją. Czy kiedykolwiek była dyskusja na temat dodania go do standardu C ++, a jeśli tak, to dlaczego został pominięty?

Niektóre potencjalne przyczyny:

  • Owłosione dla dostawców kompilatora do wdrożenia
  • Niezgodny z inną częścią standardu
  • Funkcjonalność można emulować za pomocą innych konstrukcji C ++

Standard C ++ stwierdza, że ​​rozmiar tablicy musi być stałym wyrażeniem (8.3.4.1).

Tak, oczywiście zdaję sobie sprawę, że w przykładzie z zabawką można by użyć std::vector<int> values(m);, ale to przydziela pamięć ze stosu, a nie ze stosu. A jeśli chcę wielowymiarową tablicę, taką jak:

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

vectorwersja staje się całkiem niezdarna:

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

Plasterki, wiersze i kolumny będą również potencjalnie rozłożone w całej pamięci.

Patrząc na dyskusję comp.std.c++, widać wyraźnie, że to pytanie jest dość kontrowersyjne z niektórymi bardzo ważnymi nazwami po obu stronach argumentu. Z pewnością nie jest oczywiste, że a std::vectorjest zawsze lepszym rozwiązaniem.

Andreas Brinck
źródło
3
Właśnie z ciekawości, dlaczego trzeba go przypisać do stosu? Czy boisz się problemów z wydajnością alokacji sterty?
Dimitri C.,
32
@Dimitri Nie bardzo, ale nie można zaprzeczyć, że alokacja stosu będzie szybsza niż alokacja sterty. W niektórych przypadkach może to mieć znaczenie.
Andreas Brinck,
11
Główną zaletą tablic o zmiennej długości jest to, że wszystkie dane są blisko siebie, więc podczas iteracji w tej tablicy odczytujesz i zapisujesz bajty obok siebie. Twoje dane są pobierane do pamięci podręcznej i procesor może na nich pracować bez pobierania i wysyłania bajtów do / z pamięci.
Calmarius
4
Tablice o zmiennej długości mogą być również stosowane do zastępowania stałych preprocesora zmiennymi stałymi statycznymi. Również w C nie masz innych opcji dla VLA i czasami trzeba napisać przenośny kod C / C ++ (kompatybilny z oboma kompilatorami).
Wczoraj,
2
na marginesie wydaje się, że clang ++ pozwala na VLA.
user3426763

Odpowiedzi:

204

Niedawno odbyła się dyskusja na ten temat w usenet: Dlaczego nie ma VLA w C ++ 0x .

Zgadzam się z tymi osobami, które wydają się zgadzać, że tworzenie potencjalnie dużej tablicy na stosie, która zwykle ma niewiele miejsca, nie jest dobre. Argumentem jest, że jeśli znasz wcześniej rozmiar, możesz użyć tablicy statycznej. A jeśli nie znasz wcześniej rozmiaru, napiszesz niebezpieczny kod.

C99 VLA mogłyby zapewnić niewielką korzyść z możliwości tworzenia małych tablic bez marnowania miejsca lub wywoływania konstruktorów dla nieużywanych elementów, ale wprowadzą dość duże zmiany w systemie typów (musisz być w stanie określić typy w zależności od wartości środowiska wykonawczego - to nie istnieje jeszcze w obecnym C ++, z wyjątkiem newspecyfikatorów typu operatora, ale są one traktowane specjalnie, aby środowisko wykonawcze nie wymykało się zakresowi newoperatora).

Możesz użyć std::vector, ale nie jest to to samo, ponieważ używa pamięci dynamicznej, a użycie własnego alokatora stosu nie jest łatwe (wyrównanie również stanowi problem). Nie rozwiązuje również tego samego problemu, ponieważ wektor jest pojemnikiem o zmiennym rozmiarze, podczas gdy VLA mają stały rozmiar. Propozycja C ++ Dynamic Array ma na celu wprowadzenie rozwiązania opartego na bibliotece, jako alternatywy dla VLA opartego na języku. Jednak, o ile mi wiadomo, nie będzie to część C ++ 0x.

Johannes Schaub - litb
źródło
22
+1 i zaakceptowane. Jeden komentarz, ale myślę, że argument bezpieczeństwa jest trochę słaby, ponieważ istnieje wiele innych sposobów powodowania przepełnienia stosu. Argument bezpieczeństwa może być wykorzystany do poparcia stanowiska, że ​​nigdy nie należy używać rekurencji i że należy przydzielić wszystkie obiekty ze sterty.
Andreas Brinck,
17
Mówisz więc, że ponieważ istnieją inne sposoby powodowania przepełnienia stosu, równie dobrze możemy zachęcić ich więcej?
lipiec
3
@Andreas, zgodził się co do słabości. Ale w przypadku rekurencji potrzeba ogromnej liczby wywołań, aż stos zostanie zjedzony, a jeśli tak się stanie, ludzie skorzystaliby z iteracji. Jednak, jak twierdzą niektórzy ludzie w wątku usenet, nie jest to argument przeciwko VLA we wszystkich przypadkach, ponieważ czasami na pewno możesz znać górną granicę. Ale w tych przypadkach, z tego, co widzę, statyczna tablica może być równie wystarczająca, ponieważ i tak nie zmarnowałaby dużo miejsca (gdyby tak było , musiałbyś zapytać, czy obszar stosu jest znowu wystarczająco duży).
Johannes Schaub - litb
10
Spójrz także na odpowiedź Matta Austerna w tym wątku: Specyfikacja języka VLA byłaby prawdopodobnie znacznie bardziej złożona dla C ++, ze względu na bardziej ścisłe dopasowanie typów w C ++ (przykład: C pozwala przypisać a T(*)[]do T(*)[N]- w C ++ nie jest to dozwolone, ponieważ C ++ nie wie o „kompatybilności typów” - wymaga dokładnych dopasowań), parametrów typu, wyjątków, konstruktorów i destruktorów i innych rzeczy. Nie jestem pewien, czy korzyści płynące z VLA naprawdę spłaciłyby całą tę pracę. Ale nigdy nie korzystałem z VLA w prawdziwym życiu, więc prawdopodobnie nie znam dla nich dobrych przypadków użycia.
Johannes Schaub - litb
1
@AHelps: Być może najlepszym rozwiązaniem byłby typ, który zachowuje się nieco podobnie, vectorale wymaga stałego wzorca użytkowania LIFO i utrzymuje jeden lub więcej statycznie przydzielonych buforów dla wątku, które są ogólnie wielkości zgodnie z największą całkowitą alokacją, jaką ma wątek kiedykolwiek używane, ale które można wyraźnie przyciąć. Normalna „alokacja” w zwykłym przypadku wymagałaby jedynie kopiowania wskaźnika, odejmowania wskaźnika od wskaźnika, porównywania liczb całkowitych i dodawania wskaźnika; alokacja wymagałaby po prostu kopii wskaźnika. Niewiele wolniejszy niż VLA.
supercat
216

(Tło: Mam doświadczenie w implementacji kompilatorów C i C ++.)

Tablice o zmiennej długości w C99 były w zasadzie błędem. Aby wesprzeć VLA, C99 musiał poczynić następujące ustępstwa wobec zdrowego rozsądku:

  • sizeof xnie jest już zawsze stałą czasową kompilacji; kompilator musi czasem wygenerować kod, aby ocenić sizeof-wyrażenie w czasie wykonywania.

  • Pozwalając Włas dwuwymiarowe ( int A[x][y]) wymagane nową składnię deklarowania funkcji, które mają 2D Włas jako parametry: void foo(int n, int A[][*]).

  • Mniej ważne w świecie C ++, ale niezwykle ważne dla docelowej grupy C programistów systemów wbudowanych, zadeklarowanie VLA oznacza przełamanie dowolnej dużej części stosu. Jest to gwarantowane przepełnienie stosu i awaria. (Zawsze możesz zadeklarować int A[n], jesteś pośrednio twierdząc, że masz 2GB stosu oszczędzić. Po tym wszystkim, jeśli znasz „ njest zdecydowanie mniej niż 1000 Here”, wtedy po prostu zadeklarować int A[1000]. Podstawiając 32-bitową liczbę całkowitą nza 1000to wstęp że nie masz pojęcia, jakie powinno być zachowanie twojego programu).

OK, przejdźmy teraz do rozmowy o C ++. W C ++ mamy takie samo rozróżnienie pomiędzy „systemem typów” i „systemem wartości”, co C89… ale tak naprawdę zaczęliśmy na nim polegać w sposób, w jaki C nie. Na przykład:

template<typename T> struct S { ... };
int A[n];
S<decltype(A)> s;  // equivalently, S<int[n]> s;

Gdyby nnie była stała czasowa kompilacji (tj. Gdyby Abyła zmiennie zmodyfikowanego typu), to czym, u licha, byłby typ S? Czy Styp byłby również określany tylko w czasie wykonywania?

A co z tym:

template<typename T> bool myfunc(T& t1, T& t2) { ... };
int A1[n1], A2[n2];
myfunc(A1, A2);

Kompilator musi wygenerować kod dla określonej instancji myfunc. Jak powinien wyglądać ten kod? Jak możemy statycznie wygenerować ten kod, jeśli nie znamy typu A1w czasie kompilacji?

Co gorsza, co się stanie, jeśli okaże się to w czasie wykonywania n1 != n2, tak !std::is_same<decltype(A1), decltype(A2)>()? W takim przypadku wywołanie do myfunc nie powinno się nawet kompilować , ponieważ dedukcja typu szablonu powinna zakończyć się niepowodzeniem! Jak możemy naśladować to zachowanie w czasie wykonywania?

Zasadniczo C ++ zmierza w kierunku popychania coraz większej liczby decyzji do czasu kompilacji : generowania kodu szablonu, constexproceny funkcji i tak dalej. Tymczasem C99 był zajęty popychanie tradycyjnie kompilacji decyzje (np sizeof) do wykonywania . Mając to na uwadze, czy naprawdę warto w ogóle podejmować wysiłki, próbując zintegrować VLA w stylu C99 z C ++?

Jak już zauważył każdy inny odpowiadający, C ++ zapewnia wiele mechanizmów alokacji sterty ( std::unique_ptr<int[]> A = new int[n];lub std::vector<int> A(n);oczywiste), gdy naprawdę chcesz przekazać ideę „Nie mam pojęcia, ile pamięci RAM może potrzebować”. A C ++ zapewnia sprytny model obsługi wyjątków do radzenia sobie z nieuchronną sytuacją, w której potrzebna ilość pamięci RAM jest większa niż ilość pamięci RAM, którą masz. Ale mam nadzieję, że ta odpowiedź daje dobre wyobrażenie o tym, dlaczego VLA w stylu C99 nie pasowały do ​​C ++ - a nawet nie pasowały do ​​C99. ;)


Aby uzyskać więcej informacji na ten temat, patrz N3810 „Alternatywy dla rozszerzeń macierzy” , artykuł Bjarne Stroustrup z października 2013 r. Na temat VLA. POV Bjarne'a bardzo różni się od mojego; N3810 skupia się bardziej na znalezieniu dobrej składni języka C ++ dla rzeczy i na zniechęcaniu do używania surowych tablic w C ++, podczas gdy bardziej skupiłem się na implikacjach dla metaprogramowania i systemu typów. Nie wiem, czy uważa, że ​​implikacje metaprogramowania / systemu typów są rozwiązane, możliwe do rozwiązania lub po prostu nieciekawe.


Dobry post na blogu, który dotyka wielu z tych samych punktów, to „Uzasadnione użycie tablic o zmiennej długości” (Chris Wellons, 27.10.2019).

Quuxplusone
źródło
15
Zgadzam się, że VLA były po prostu złe. Znacznie szerzej zaimplementowana i znacznie bardziej użyteczna alloca()powinna była zamiast tego zostać znormalizowana w C99. VLA mają miejsce, gdy komitet normalizacyjny wyskakuje przed implementacją, a nie na odwrót.
MadScientist
10
Zmodyfikowany system typów jest świetnym dodatkiem IMO i żaden z twoich punktów nie narusza zdrowego rozsądku. (1) standard C nie rozróżnia między „czasem kompilacji” a „czasem wykonywania”, więc nie stanowi to problemu; (2) *Jest opcjonalny, możesz (i powinieneś) pisać int A[][n]; (3) Możesz używać systemu typów bez faktycznego deklarowania VLA. Na przykład funkcja może przyjmować tablicę zmiennych typów i może być wywoływana z tablicami innymi niż VLA 2-D o różnych wymiarach. Jednak robisz ważne punkty w drugiej części swojego postu.
MM
3
„zadeklarowanie VLA oznacza zgryzienie dowolnie dużego fragmentu stosu. Jest to gwarantowane przepełnienie stosu i awaria. (Za każdym razem, gdy zadeklarujesz int A [n], domyślnie zapewniasz, że masz 2 GB stosu do oszczędzenia” jest empirycznie false. Właśnie uruchomiłem program VLA ze stosem znacznie mniejszym niż 2 GB bez przepełnienia stosu
Jeff
3
@Jeff: Jaka była maksymalna wartość nw twoim przypadku testowym i jaki był rozmiar twojego stosu? Sugeruję, aby spróbować wprowadzić wartość nco najmniej tak dużą, jak rozmiar stosu. (A jeśli użytkownik nie ma możliwości kontrolowania wartości nw twoim programie, sugeruję, abyś po prostu propagował maksymalną wartość nprosto do deklaracji: deklaruj int A[1000]lub cokolwiek jest potrzebne. VLA są tylko konieczne i niebezpieczne, gdy maksymalna wartość nnie jest ograniczona żadną małą stałą czasową kompilacji.)
Quuxplusone
2
Ponieważ alokację () można zaimplementować za pomocą takich wewnętrznych elementów, z definicji prawdą jest, że alokację () można zaimplementować na dowolnej platformie, jako standardowej funkcji kompilatora. Nie ma powodu, dla którego kompilator nie mógł wykryć pierwszej instancji przydziału () i zorganizować typy znaków i wydań, które mają być osadzone w kodzie, i nie ma powodu, dla którego kompilator nie może zaimplementować przydziału sterty () przy użyciu sterty, jeśli nie można tego zrobić ze stosem. Co jest trudne / non-Portable to mieć alloca () realizowane na szczycie kompilator C, tak, że działa na szerokiej gamie kompilatorów i systemów operacyjnych.
MadScientist
26

Zawsze możesz użyć przydziału () do przydzielenia pamięci na stosie w czasie wykonywania, jeśli chcesz:

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

Przydział na stosie oznacza, że ​​zostanie on automatycznie uwolniony, gdy stos się odwija.

Szybka uwaga: Jak wspomniano na stronie podręcznika systemowego Mac OS X dla programu Alba (3), „Funkcja Alcala () zależy od maszyny i kompilatora; jej użycie jest zniechęcone”. Tak, żebyś wiedział.

PfhorSlayer
źródło
4
Poza tym zasięgem funkcji replacea () jest cała funkcja, a nie tylko blok kodu zawierający zmienną. Zatem użycie go w pętli spowoduje ciągłe zwiększanie stosu. VLA nie ma tego problemu.
sashoalm
3
Jednak VLA posiadające zakres otaczającego bloku oznaczają, że są one znacznie mniej przydatne niż przydział () z zakresem całej funkcji. Zastanów się: if (!p) { p = alloca(strlen(foo)+1); strcpy(p, foo); } nie można tego zrobić z VLA, właśnie ze względu na ich zakres blokowy.
MadScientist
1
To nie odpowiada na pytanie dlaczego OP . Co więcej, jest to Crozwiązanie podobne do rzeczywistego, a nie bardzo C++.
Adrian W
13

W mojej własnej pracy zdałem sobie sprawę, że za każdym razem, gdy chciałem czegoś takiego, jak tablice automatyczne o zmiennej długości lub alga (), tak naprawdę nie obchodziło mnie, że pamięć fizycznie znajduje się na stosie procesora, tylko że pochodzi od jakiś rozdzielacz stosu, który nie powodował powolnych podróży na stos ogólny. Mam więc obiekt na wątek, który posiada pewną pamięć, z której może pchać / pop bufory o zmiennej wielkości. Na niektórych platformach zezwalam na to przez MMU. Inne platformy mają stały rozmiar (zwykle towarzyszy temu również stały rozmiar procesora, ponieważ nie ma mmu). Jedna platforma, z którą pracuję (podręczna konsola do gier) ma zresztą cenny mały stos procesorów, ponieważ znajduje się w rzadkiej, szybkiej pamięci.

Nie twierdzę, że wrzucanie buforów o zmiennej wielkości do stosu procesorów nigdy nie jest potrzebne. Szczerze mówiąc, byłem zaskoczony, gdy odkryłem, że nie jest to standard, ponieważ z pewnością wydaje się, że koncepcja dobrze pasuje do języka. Jednak dla mnie wymagania „zmienny rozmiar” i „muszą znajdować się fizycznie na stosie procesora” nigdy nie zostały spełnione. Chodzi o szybkość, więc stworzyłem swój własny „równoległy stos dla buforów danych”.

Eric
źródło
12

Są sytuacje, w których przydzielanie pamięci sterty jest bardzo kosztowne w porównaniu do wykonywanych operacji. Przykładem jest matematyka matematyczna. Jeśli pracujesz z małymi matrycami, powiedz od 5 do 10 elementów i wykonuj dużo arytmetyki, narzut malloc będzie naprawdę znaczący. Jednocześnie zmiana wielkości na stałą czasową kompilacji wydaje się bardzo marnotrawna i nieelastyczna.

Myślę, że C ++ sam w sobie jest tak niebezpieczny, że argument „staraj się nie dodawać więcej niebezpiecznych funkcji” nie jest zbyt silny. Z drugiej strony, ponieważ C ++ jest prawdopodobnie najbardziej wydajnym językiem programowania w środowisku wykonawczym, co czyni go bardziej użytecznym: ludzie, którzy piszą programy o kluczowym znaczeniu dla wydajności, będą w dużej mierze korzystać z C ++ i potrzebują jak największej wydajności. Jedną z takich możliwości jest przenoszenie rzeczy ze stosu na stos. Innym jest zmniejszenie liczby bloków sterty. Dopuszczenie VLA jako członków obiektów byłoby jednym ze sposobów na osiągnięcie tego. Pracuję nad taką sugestią. Wprawdzie jest to nieco skomplikowane, ale wydaje się całkiem wykonalne.

Bengt Gustafsson
źródło
12

Wygląda na to, że będzie dostępny w C ++ 14:

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

Aktualizacja: Nie wprowadzono go do C ++ 14.

Viktor Sehr
źródło
ciekawy. Herb Sutter omawia to tutaj pod Dynamic Arrays : isocpp.org/blog/2013/04/trip-report-iso-c-spring-2013-meeting (jest to odniesienie do informacji z wikipedii)
Domyślnie
1
„Tablice i dynarray o wymiarach czasu wykonywania zostały przeniesione do specyfikacji technicznej rozszerzeń macierzy”, napisał 78.86.152.103 na Wikipedii w dniu 18 stycznia 2014 r .: en.wikipedia.org/w/...
strager
10
Wikipedia nie jest odniesieniem normatywnym :) Ta propozycja nie znalazła się w C ++ 14.
MM
2
@ViktorSehr: Jaki jest status tego wrt C ++ 17?
einpoklum
@einpoklum Nie mam pojęcia, użyj boost :: container :: static_vector
Viktor Sehr
7

Zostało to rozważone pod kątem włączenia do C ++ / 1x, ale zostało porzucone (jest to poprawka do tego, co powiedziałem wcześniej).

Byłoby to mniej przydatne w C ++, ponieważ musimy już std::vectorwypełnić tę rolę.

philsquared
źródło
42
Nie, my nie, std :: vector nie alokuje danych na stosie. :)
Kos,
7
„stos” jest szczegółem implementacji; kompilator może przydzielać pamięć z dowolnego miejsca, o ile spełnione są gwarancje dotyczące żywotności obiektu.
MM
1
@MM: Fair enough, ale w praktyce nadal nie można używać std::vectorzamiast, powiedzmy alloca().
einpoklum
@einpoklum pod względem uzyskania poprawnego wyniku dla twojego programu, możesz. Wydajność jest kwestią jakości wykonania
MM
1
Jakość wykonania @MM nie jest przenośna. a jeśli nie potrzebujesz wydajności, nie używasz c ++ w pierwszej kolejności
pal
3

Użyj do tego std :: vector. Na przykład:

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

Pamięć zostanie przydzielona na stercie, ale ma to tylko niewielką wadę wydajności. Ponadto rozsądnie jest nie przydzielać dużych bloków danych na stos, ponieważ ma on raczej ograniczony rozmiar.

Dimitri C.
źródło
4
Głównym zastosowaniem tablic o zmiennej długości jest ocena wielomianów dowolnego stopnia. W takim przypadku „niewielka wada wydajności” oznacza „kod działa pięć razy wolniej w typowych przypadkach”. To nie jest małe.
AHelps
1
Dlaczego po prostu nie używasz std::vector<int> values(n);? Używając resizepo zakończeniu budowy, zabraniasz poruszania się na ruchomych typach.
LF,
1

C99 pozwala na VLA. I nakłada pewne ograniczenia na sposób deklarowania VLA. Aby uzyskać szczegółowe informacje, patrz 6.7.5.2 normy. C ++ nie zezwala na VLA. Ale g ++ pozwala na to.

Jingguo Yao
źródło
Czy możesz podać link do wskazanego standardowego akapitu?
Vincent
0

Takie tablice są częścią C99, ale nie są częścią standardowego C ++. jak powiedzieli inni, wektor jest zawsze o wiele lepszym rozwiązaniem, i prawdopodobnie dlatego tablice o zmiennej wielkości nie są w standardzie C ++ (lub w proponowanym standardzie C ++ 0x).

BTW, na pytania dotyczące „dlaczego” standard C ++ jest taki, jaki jest, moderowana grupa dyskusyjna Usenet comp.std.c ++ jest miejscem, do którego można się udać.


źródło
6
-1 Wektor nie zawsze jest lepszy. Często tak. Zawsze nie. Jeśli potrzebujesz tylko małej tablicy, znajdujesz się na platformie, na której miejsce na sterty jest wolne, a implementacja biblioteki wektorowej wykorzystuje miejsce na sterty, to ta funkcja może być lepsza, jeśli taka istnieje.
Patrick M
-1

Jeśli znasz wartość w czasie kompilacji, możesz wykonać następujące czynności:

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

}

Edycja: Możesz utworzyć wektor, który używa alokatora stosu (alokatora), ponieważ alokator jest parametrem szablonu.

Edouard A.
źródło
18
Jeśli znasz wartość w czasie kompilacji, w ogóle nie potrzebujesz szablonu. Wystarczy użyć X bezpośrednio w funkcji innej niż szablon.
Rob Kennedy,
3
Czasami dzwoniący wie w czasie kompilacji, a osoba odbierająca nie wie, do czego są odpowiednie szablony. Oczywiście w ogólnym przypadku nikt nie zna X aż do czasu wykonania.
Qwertie
Nie można używać alokacji w alokatorze STL - alokowana pamięć z alokacji zostanie zwolniona, gdy ramka stosu zostanie zniszczona - wtedy metoda, która powinna alokować pamięć, powraca.
Oliver,
-5

Mam rozwiązanie, które faktycznie dla mnie zadziałało. Nie chciałem przydzielać pamięci z powodu fragmentacji w procedurze, która musiała działać wiele razy. Odpowiedź jest bardzo niebezpieczna, więc używaj jej na własne ryzyko, ale korzysta z montażu, aby zarezerwować miejsce na stosie. Mój przykład poniżej wykorzystuje tablicę znaków (oczywiście zmienna o innym rozmiarze wymagałaby więcej pamięci).

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
    } 
}

Zagrożeń jest wiele, ale wyjaśnię kilka: 1. Zmiana wielkości zmiennej do połowy zabiłaby pozycję stosu 2. Przekroczenie granic tablicy zniszczyłoby inne zmienne i możliwy kod 3. To nie działa w 64 bitach build ... potrzebujesz innego zestawu dla tego (ale makro może rozwiązać ten problem). 4. Specyficzny dla kompilatora (może mieć problemy z przemieszczaniem się między kompilatorami). Nie próbowałem, więc naprawdę nie wiem.

Alan
źródło
... a jeśli chcesz rzucić to sam, może skorzystasz z klasy RAII?
einpoklum
Możesz po prostu użyć boost :: container :: static_vector tys.
Viktor Sehr
To nie ma odpowiedników dla innych kompilatorów, które mają bardziej surowy zestaw niż MSVC. VC prawdopodobnie zrozumie, że to się espzmieniło i dostosuje dostęp do stosu, ale np. W GCC po prostu całkowicie go złamiesz - przynajmniej jeśli korzystasz z optymalizacji, -fomit-frame-pointerw szczególności.
Ruslan