Размер массива С++, зависящий от параметра функции, вызывает ошибки компиляции
У меня есть простая функция, в которой объявлен массив с размером
в зависимости от параметра, который является int.
void f(int n){
char a[n];
};
int main() {
return 0;
}
Этот фрагмент кода отлично компилируется на GNU С++, но не на MSVC 2005.
Я получаю следующие ошибки компиляции:
.\main.cpp(4) : error C2057: expected constant expression
.\main.cpp(4) : error C2466: cannot allocate an array of constant size 0
.\main.cpp(4) : error C2133: 'a' : unknown size
Что я могу сделать, чтобы исправить это?
(Я заинтересован в том, чтобы сделать эту работу с MSVC, не используя new/delete)
Ответы
Ответ 1
Что вы нашли его одним из расширений компилятора Gnu на языке С++. В этом случае Visual С++ полностью корректен. Массивы в С++ должны быть определены с размером, являющимся выражением постоянной времени компиляции.
В обновлении 1999 года к этому языку была добавлена функция, называемая массивами переменной длины, где это является законным. Если вы можете найти компилятор C, который поддерживает C99, что непросто. Но эта функция не является частью стандартного С++, но не будет добавлена в следующее обновление к стандарту С++.
В С++ есть два решения. Первый заключается в использовании std::vector, второй - просто использовать оператор new []
:
char *a = new char [n];
Пока я писал свой ответ, другой написал предложение использовать _alloca. Я бы настоятельно рекомендовал против этого. Вы бы просто обменялись одним нестандартным, не переносным методом для другого, точно так же, как и для компилятора.
Ответ 2
Ваш метод выделения из стека - расширение g++. Чтобы выполнить эквивалент в MSVC, вам необходимо использовать _alloca:
char *a = (char *)_alloca(n);
Ответ 3
Вы используете то, что не является стандартом. На самом деле это стандартный C, но не С++. Как это странно!
Объясняя немного больше, массивы стека времени выполнения не являются частью С++, но являются частью C99, последнего стандарта для C. Вот почему некоторые компиляторы получат его, а другие - нет. Я бы рекомендовал воздержаться от его использования, чтобы избежать проблем с совместимостью компилятора.
Альтернативная реализация функциональности будет использовать новые и удалить, как опубликовано strager.
Ответ 4
массив переменной длины был введен в C99. Он поддерживается в gcc, но не msvc. По словам человека в команде MSVC, Microsoft не планирует поддерживать эту функцию в своем компиляторе c/С++. Он предложил использовать std::vector в этих случаях.
Обратите внимание, что C99 не требует, чтобы массив был выделен в стеке. Компилятор может выделить его в кучу. Однако gcc выделяет массив в стеке.
Ответ 5
Вы можете использовать new/delete для выделения/свободной памяти в куче. Это медленнее и, возможно, больше подвержено ошибкам, чем использование char [n], но пока оно не является частью стандарта С++, к сожалению.
Вы можете использовать класс массива с расширенным охватом для безопасного для исключения метода использования нового []. delete [] автоматически вызывается в случае, когда он выходит из области видимости.
void f(int n) {
boost::scoped_array<char> a(new char[n]);
/* Code here. */
}
Вы также можете использовать std::vector и зарезервировать() несколько байтов:
void f(int n) {
std::vector<char> a;
a.resize(n);
/* Code here. */
}
Если вы хотите использовать char [n], скомпилируйте как код C99 вместо кода на С++.
Если вам по какой-то причине необходимо выделить данные в стеке, используйте _alloca или _malloca/_freea, которые являются расширениями, предоставляемыми библиотеками MSVC и т.д.
Ответ 6
Обычно в C (кроме компиляторов C99, как указывали другие) и С++, если вы хотите выделить память в стеке, размер того, что вы хотите выделить, должен быть известен во время компиляции. Локальные переменные выделяются в стеке, поэтому массив, длина которого зависит от параметра функции во время выполнения, нарушает это правило. Клейн правильно указал, что использование "нового" оператора является одним из способов решения этой проблемы:
char *a = new char [n];
'a' is still a local variable allocated on the stack, but instead of being the whole array (which has variable length), it just a pointer to an array (which is always the same size, and thus known at compile time). The array is allocated on the heap, which typically plays the stack counterpart -- the stack is for things with a size known at compile time, and the heap is for things with a size not known at a compile time.
Ответ 7
Можно ли использовать vector<>
вместо массива? Или, поскольку вы заменяете char *
, a std::string
? Это хорошо работает с определением времени выполнения, хотя могут быть и другие причины не использовать их.