Размер массива С++ без постоянных выражений
Я читаю Stroustrup's Тур по С++. На стр. 9 он утверждает:
"Размер массива должен быть постоянным выражением".
Но позже, на стр. 16, он использует следующий пример кода:
void vector vector_init(Vector& v, int s)
{
v.elem = new double[s]; // Allocate an array of s doubles
v.sz = s;
}
Здесь s
не является постоянным выражением, так как инициализируется v.elem
до new double[s]
legal?
Ответы
Ответ 1
Существует дифференциация между выделенными массивами (т.е. созданная с выражением new[]
, например new double[s]
), время жизни которой должно управляться кодом (через delete[]
) и объявленными массивами, время жизни которых управляется только их объем:
int* p = new int[s]; // allocated array, p has type int*
int q[10]; // declared array, q has type int[10]
std::vector<int> u; // has member allocated array
std::array<int, 5> v; // has member declared array
Дифференциация не основана на стеке/куче. Объявленный массив может быть выделен в виде кучи (например, new array<int,5>
) или нет в стеке (например, static double x[100];
)
С выделенным массивом размер не обязательно должен быть постоянным выражением. Размер будет просто закодирован в блок памяти, предоставленный распределителем каким-то образом (например, четыре ведущих байта перед началом фактических данных), так что соответствующий delete[]
знает, сколько элементов нужно удалить.
С объявленным массивом (или не выделенным массивом, no new
/malloc
/etc.) размер должен быть & dagger; закодирован в тип, так что деструктор знает что делать. Разрешено только стандартное объявление массива:
T D[constant-expression_opt];
(где D
- декларатор, который может быть именем или другим объявлением массива и т.д.) Объявленные массивы не ограничены стеком. Обратите внимание, что для дополнительной путаницы константное выражение необязательно.
Массивы предлагают множество источников замешательства в С++. Выделенные и объявленные массивы имеют разные правила размера, разные методы управления, но вы можете назначить T*
для обоих, и они будут индексироваться эквивалентно. Выделенный массив - это указатель (все, что вы получаете), но объявленный массив распадается на указатель (но это массив!).
& dagger; Обратите внимание, что существует понятие Variable Length Array (VLA). gcc, например, поддерживает их как расширение, но они нестандартные С++. Он периодически предлагается, и вы можете увидеть этот вопрос для получения дополнительной информации о них.
Ответ 2
При создании массива, память которого управляется компилятором, его размер должен быть константой (время компиляции). Для примера:
int a[5];
const int sz = 7;
int b[sz] = {0};
(Некоторые языки для ex: C (C99) поддерживают динамический размер массива)
Если вам нужен массив динамического размера (пример фрагмента, предоставленный вами), вам нужно выделить память для него самостоятельно, вам также понадобится освободить его с помощью delete
, когда вы закончите. Размер таких массивов также может быть неконстантным. Кроме того, вам нужно управлять памятью самостоятельно, распределение может завершиться неудачей, и операторы (например, sizeof
) будут работать с указателем, а не с массивом.
В современном С++ (С++ 11 и далее) даже stl container std::array
должен иметь постоянный размер.
Ответ 3
Цитата
Размер массива должен быть постоянным выражением.
говорит о объявлении массива, например
double a[EXPR];
где EXPR
действительно должно быть константой или constexpr (C имеет массивы переменной длины, но они не являются частью стандартного С++).
Выражение, которое вы упоминаете как встречный пример,
new double[s]
не является массивом, несмотря на []
. Это новое выражение и дает указатель, а не массив. Вы не указали определение v.elem
, но я могу указать ему указатель на двойной.
Примечание из связанного обсуждения новых выражений, которые
Если type является типом массива, все измерения, отличные от первого, должны быть указаны как положительные {что-то вроде интегральной константы - детализация нажата}.
Таким образом, упомянутый выше тип double[s]
, который явно разрешен.
Разумеется, разница между массивом и типом массива, переданным новому выражению, немного тонкая, но вы не можете скрыть их только из-за []
, больше, чем вы можете утверждать, что
map["key"]
что-то нарушает, объявляя массив длиной "key"
.