Почему в массиве нет массива переменных размеров?

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

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

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

Ответы

Ответ 1

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

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


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

Ответ 2

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

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

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

#include <dynarray>

void func(int n)
{
    std::dynarray<int> arr(n);
}

Ответ 3

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

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

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];

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

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

Ответ 4

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

Ответ 5

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

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

Ответ 6

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

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

Ответ 7

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