2016-10-11 5 views
1

Почему я не могу написать следующее?Почему невозможно выделить массив произвольного размера в стеке?

char acBuf[nSize]; 

Только для предотвращения переполнения стека? Или есть возможность сделать что-то подобное, если я могу обеспечить, чтобы я всегда принимал всего несколько сотен килобайт?

Насколько я знаю, std::string использует память своих членов для хранения назначенных строк, если они составляют 15 символов или меньше. Только если строки длиннее, он использует эту память для хранения адреса некоторой памяти, выделенной кучей, которая затем берет данные.

Похоже, что во время компиляции он должен быть установлен на 100%, как стек будет выровнен во время выполнения. Это правда? Почему это?

+0

Да, это правда. C++ не поддерживает VLA. –

+0

Если вы выделяете стек, (теоретически), вся память для каждого стекового кадра выделяется в начале его области, поэтому у нас есть динамическое хранилище, где память распределяется с использованием бесплатного хранилища. – George

ответ

1

В отличие от C, C++ не поддерживает массивы переменной длины. Если вы хотите, вы можете использовать нестандартные расширения, такие как alloca или расширения GNU (поддерживаемые clang и GCC). У них есть свои предостережения, поэтому обязательно прочтите руководство, чтобы убедиться, что вы используете их безопасно.

Причина, по которой статическая компоновка в основном определяется статически, заключается в том, что сгенерированный код должен выполнять меньше вычислений (добавлений, умножений и разыменования указателей), чтобы выяснить, где находятся данные в стеке. Вместо этого смещения могут быть жестко закодированы в сгенерированный машинный код.

+0

Но когда я следую этому: http://stackoverflow.com/a/5770919/1594594 Я все еще не могу использовать VLA :( – Allgaeuer

1

Это не имеет никакого отношения к предотвращению переполнения стека, вы можете полностью переполнить стек с помощью char a[SOME_LARGE_CONSTANT]. В C++ размер массива должен быть известен во время компиляции, это, помимо прочего, необходимо для вычисления размера структур, содержащих массивы.

С другой стороны, с переменными длиной массивов C99, с добавлением исключения и разрешающим зависящим от времени размером для массивов в пределах области действия. Что касается того, почему у C++ этого нет? Он никогда не был принят стандартом C++.

+0

Но когда я следую этому: http://stackoverflow.com/a/5770919/1594594 I Я все еще не могу использовать VLA :( – Allgaeuer

+0

@Allgaeuer Реализация C Microsoft Visual Studio не поддерживает VLA. – Banex

+0

@Allgaeuer в вашей ссылке упоминается ANSI C, который является C90. Microsoft никогда не предоставляла полную реализацию C99, я думаю, что они поддерживают только подмножество для C++. Последняя ссылка в этом ответе также упоминает, что VLA не поддерживаются. – josefx

1

Почему я не могу написать следующее?

char acBuf[nSize]; 

Те, которые называются массивы переменной длины (VLA), и не поддерживаются C++. Причина в том, что стек очень быстрый, но крошечный по сравнению с бесплатным хранилищем (куча в ваших словах). Это означает, что в любой момент, когда вы добавляете много элементов в VLA, ваш стек может просто переполняться, и вы получаете неопределенное исключение во время выполнения. Это также может происходить с массивами стека размера компиляции, но их легче поймать, потому что поведение программы не влияет на их размер. Это означает, что x не должно произойти после y, чтобы создать переполнение стека, оно просто с самого начала. This охватывает его более подробно и ярость.

Контейнеры, такие как std::vector, используют бесплатный магазин, который больше дорог и имеет способ справиться с перераспределением (броски bad_alloc).

+1

Я собирался изменить «detail and _rage_» на «detail and _range_», но после прочтения связанного обсуждения нет опечатки для исправления. VLA обязательно воспитывайте горячие дискуссии! – tucuxi

0

Мой совет взглянуть на alloca.h

void *alloca(size_t size); 

Функция ALLOCA() выделяет размер байтов пространства в стеке кадра вызывающего абонента. Это временное пространство автоматически освобождается , когда функция, называемая alloca(), возвращается к ее вызывающей стороне.

0

Одной из возможных проблем, которые я вижу с VLA в C++, является тип.

Что такое acBuf в char acBuf[nSize] или еще хуже в char acBuf[nSize][nSize]?

template <typename T> void foo(const T&); 

void foo(int n) 
{ 
    char mat[n][n]; 

    foo(mat); 
} 

Вы не можете передать этот массив по ссылке на

template <typename T, std::size_t N> 
void foo_on_array(const T (&a)[N]); 
0

Вы должны быть счастливы, что стандарт C++ отпугивает опасная практика (массивы переменной длины в стеке), и вместо этого поощряет менее опасную практику (массивы переменной длины и std :: vector с распределением кучи).

массивы переменной длины в стеке более опасны, потому что:

  • Имеющийся стека, как правило, 8 МБ, намного меньше, чем 2 Гб (или больше) свободного пространства кучи.
  • Когда пространство стека исчерпано, программа вылетает с SIGSEGV, и для восстановления после такой ситуации требуется специальное программное обеспечение, такое как GNU libsigsegv.
  • В типичных программах на С ++ программист не знает, будет ли длина массива определенно оставаться под лимитом, например, 4 МБ.
0

Почему я не могу написать следующее? char acBuf[nSize];

Вы не можете сделать это, потому что в C++ длина массива должна быть известна во время компиляции, это потому, что компилятор сохраняет заданную память для массива и он не может быть изменен во время выполнения. это не о предотвращении переполнения стека, а о макете памяти.

Если вы хотите создать динамический массив, вы должны использовать оператор new, чтобы он хранился в куче.

char *acBuf = new char[nsize];