Почему С++ не поддерживает динамические массивы в стеке?

В C99 это было законно:

void f(size_t sz) {
    char arr[sz];
    // ...
}

Однако это - массивы стеков с динамическим размером - были сброшены на С++ и не видели возврата в С++ 11.

AFAIK С++ был сделан с учетом совместимости с C, поэтому я задавался вопросом. Должен быть какой-то очень хороший аргумент, не включающий эту полезную функцию, правильно?

Все, что я мог подумать, было следующим:

Pros

  • Экономия памяти за счет более разумного размера массива, который должен быть в стеке (временные буферы?).
  • Меньше "умных указателей" (или, что еще хуже, ручной ввод ошибок delete []) и медленные распределения кучи.
  • Совместимость с C99.

Против

  • Позволяет людям легко выделять слишком большие массивы в стеке, что позволяет переполнять.
  • Сложнее для компиляторов.

Итак, почему они не включили его, когда импортировали другие функции C99?


Чтобы это не было закрыто как "субъективное" или "не конструктивное", я ищу цитаты из членов сообщества или ссылки на обсуждения, рассказывающие об этом, - с бонусами для быстрого SO-раунда, конечно.

Вместо того, чтобы рассматривать это как обсуждение Ponies vs Hamsters, рассматривайте его как исторический вопрос, просто интересуйтесь преимуществами и недостатками, которые были рассмотрены (если вообще).


РЕДАКТИРОВАТЬ. Как отметил Джеймс Макнеллис в комментариях ниже, С++ существовал до стандартизированных массивов переменной длины C99. Вы могли бы прочитать мой вопрос, а затем: " Почему они не добавили его?".

Ответ 1

Я думаю, это потому, что С++ предлагает превосходные решения: std::vector<T> и std::array<T,N> (С++ 11); хотя последнее не является динамическим как таковое, но превосходит исходные массивы. Вы всегда можете знать размер, независимо от того, какую функцию вы передаете вектор или массив.

Так как C не может предоставить эти решения, C99 появился с переменной длиной массива (VLA). Он имеет ту же проблему, что и обычные массивы: он распадается на указатель на передачу его функции, и вы больше не знаете размер массива.

И как Florian Weimer спросил здесь в comp.std.c++, что если С++ 0x разрешает VLA, то что будет означать следующий код?

int vla[n]; //n is known at runtime!
std::vector<decltype(vla)> v; //what does this mean?

Как компилятор собирается создать экземпляр шаблона вектора во время компиляции, когда аргумент типа type зависит от n, который известен во время выполнения?

Ответ 2

Эта функция в основном дублирует функцию std::vector, за исключением того, что она потребляет более ограниченный ресурс (стек против пространства кучи). Таким образом, в С++ нет необходимости в семантике.

Можно утверждать, что выделение в стеке может повысить эффективность (особенно в случае нескольких потоков); однако это также может быть достигнуто на С++ с использованием пользовательских распределителей для создания пула частных хранилищ, либо в стеке, либо в куче. Это снова более гибко, чем размещение памяти в стеке, и действительно, вы можете создать собственный распределитель, который легко вырезает куски из буфера памяти на стеке. Это не то же самое, что и семантика динамических массивов, но наличие пользовательских распределителей и контейнеров STL охватывает большинство случаев использования, для которых требуется распределение стека.