Подтвердить что ты не робот

Размер массива С++ без постоянных выражений

Я читаю 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?

4b9b3361

Ответ 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".