Почему нет массива переменного размера в стеке? - PullRequest
20 голосов
/ 18 октября 2011

Я не совсем понимаю, почему у меня не может быть массива переменного размера в стеке, поэтому что-то вроде

foo(int n) {
   int a[n];
}

Как я понимаю, стек (-сегмент) части сегмента данных и, следовательно, он не имеет "постоянного размера".

Ответы [ 7 ]

23 голосов
/ 18 октября 2011

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

C ++ предоставляет std :: vector для реализации функциональности, аналогичной VLA .


Было предложение о введении массивов переменной длины в C ++ 11, но в итоге оно было отброшено, поскольку для него потребовались бы большие изменения в системе типов в C ++. Преимущество возможности создавать небольшие массивы в стеке без потери пространства или вызова конструкторов для неиспользуемых элементов было сочтено недостаточно значительным для больших изменений в системе типов C ++.

7 голосов
/ 01 мая 2013

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

VLA, как описано в N3639, было принято на собрании в Бристоле и станет частью C ++ 14, а также библиотечной копии "dynarray". Поэтому, используя компилятор с поддержкой C ++ 14, мы можем начать писать что-то вроде:

void func(int n)
{
    int arr[n];
}

Или используйте dynarray:

#include <dynarray>

void func(int n)
{
    std::dynarray<int> arr(n);
}
5 голосов
/ 18 октября 2011

Я попытаюсь объяснить это на примере:

Скажем, у вас есть эта функция:

int myFunc() {
   int n = 16;
   int arr[n];
   int k = 1;
}

Когда программа запускается, она устанавливает переменные таким образом в стек:

- n @relative addr 0
- arr[16] @relative addr 4
- k @relative addr 64
TOTAL SIZE: 68 bytes

Допустим, я хочу изменить размер arr до 4 элементов. Я собираюсь сделать:

delete arr;
arr = new int[4];

Теперь: если я оставлю стек таким образом, в стеке будут дыры неиспользуемого пространства. Поэтому самое разумное, что нужно сделать - это переместить все переменные из одного места в другое в стеке и пересчитать их позиции. Но нам чего-то не хватает: C ++ не устанавливает позиции на лету, это делается только один раз, когда вы компилируете программу. Зачем? Это просто: потому что нет реальной необходимости иметь объекты переменного размера в стеке, и потому что их наличие замедлит все программы при выделении / перераспределении стекового пространства.

Это не единственная проблема, есть другая, еще большая проблема: Когда вы выделяете массив, вы решаете, сколько места он займет, и компилятор может предупредить вас, если вы превысите доступное пространство, вместо этого, если вы позволите программе распределять массивы переменного размера в вашем стеке, вы открываете нарушения в безопасности, так как сделать все программы, использующие этот метод, уязвимыми для переполнения стека.

2 голосов
/ 18 октября 2011

Простой ответ: потому что он не определен в стандарте C ++.

Не такой простой ответ: потому что никто не высказал предположения о том, что в таком случае C ++ будет вести себя согласованно.Из стандартов POV нет стека, он может быть реализован совершенно иначе.В C99 есть VLA, но их реализация настолько сложна, что gcc завершил реализацию только в 4.6.Я не думаю, что многие люди захотят предложить что-то для C ++ и увидят, как производители компиляторов борются с этим в течение многих лет.

2 голосов
/ 18 октября 2011

Потому что так сказано в спецификации языка. Ничто другое не имеет значения (и объяснение с помощью сегментов ужасно неправильно по разным причинам).

1 голос
/ 18 октября 2011

Стеки довольно малы, и их размеры могут сильно различаться в зависимости от архитектуры.Проблема в том, что довольно легко «перераспределить» и вызвать ошибку сегмента или перезаписать память, принадлежащую кому-то другому.Между тем, решения проблемы (например, vector) существуют в течение длительного времени.

FWIW, я читал, что Страуструп говорит, что он не хочет их, но я незнать, в каком интервью оно было.

0 голосов
/ 18 октября 2011

Поскольку в C ++ статическому массиву требуется статический постоянный размер, он не допускается языком.Обратите внимание, что C99 поддерживает vararrays в стеке, и некоторые реализации поддерживают его как в C ++, так и в расширении.

...