C++ new int[0] - будет ли он выделять память?

Простое тестовое приложение:

cout << new int[0] << endl;

выходы:

0x876c0b8

Похоже, это работает. Что стандарт говорит об этом? Всегда ли законно "выделять" пустой блок памяти?

5 ответов

Решение

От 5.3.4/7

Когда значение выражения в direct-new-таком объявителе равно нулю, функция выделения вызывается для выделения массива без элементов.

От 3.7.3.1/2

Эффект разыменования указателя, возвращаемого как запрос нулевого размера, не определен.

Также

Даже если размер запрошенного [нового] ​​пространства равен нулю, запрос может завершиться неудачно.

Это означает, что вы можете сделать это, но вы не можете юридически (четко определенным образом на всех платформах) разыменовать полученную память - вы можете только передать ее в удаление массива - и вы должны удалить ее.

Вот интересная сноска (то есть не нормативная часть стандарта, но включенная в пояснительных целях), приложенная к предложению из 3.7.3.1/2

[32. Намерение состоит в том, чтобы оператор new() мог быть реализован путем вызова malloc() или calloc(), так что правила практически одинаковы. C++ отличается от C тем, что требует нулевого запроса для возврата ненулевого указателя.]

Да, это законно, чтобы выделить массив нулевого размера, как это. Но вы также должны удалить его.

Что стандарт говорит об этом? Всегда ли законно "выделять" пустой блок памяти?

Каждый объект имеет уникальную идентичность, то есть уникальный адрес, который подразумевает ненулевую длину (фактический объем памяти будет незаметно увеличен, если вы запросите нулевые байты).

Если вы разместите более одного из этих объектов, вы обнаружите, что они имеют разные адреса.

Да, это совершенно законно, чтобы выделить 0 размер блока с new, Вы просто не можете сделать что-нибудь полезное с этим, так как для вас нет действительных данных. int[0] = 5; незаконно

Тем не менее, я считаю, что стандарт допускает такие вещи, как malloc(0) возвращать NULL,

Вам все еще нужно будет delete [] любой указатель, который вы получите от распределения.

Я гарантирую вам, что новый int[0] требует дополнительного места, так как я его тестировал.

Например, использование памяти

int **arr = new int*[1000000000];

значительно меньше, чем

int **arr = new int*[1000000000];
for(int i =0; i < 1000000000; i++) {
    arr[i]=new int[0];
}

Использование памяти вторым фрагментом кода за вычетом первого фрагмента кода - это память, используемая для множества новых int[0].

Любопытно, что C++ требует, чтобы оператор new возвращал законный указатель, даже когда запрашивается ноль байтов. (Требование такого странного поведения упрощает вещи в другом месте языка.)

Я обнаружил, что третье издание Effective C++ говорит так: "Правило 51: придерживайтесь соглашения при написании нового и удалении".

Другие вопросы по тегам