Почему в массиве нет массива переменных размеров?
Я действительно не понимаю, почему у меня не может быть массив переменных размера в стеке, поэтому что-то вроде
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 в стеке, а некоторые реализации поддерживают его под С++, а также расширение.