Простой тест приложение:C++ new int [0] - он будет выделять память?
cout << new int[0] << endl;
выходы:
0x876c0b8
Так это выглядит, как он работает. Что говорит об этом стандарт? Всегда ли законно «распределять» пустой блок памяти?
Простой тест приложение:C++ new int [0] - он будет выделять память?
cout << new int[0] << endl;
выходы:
0x876c0b8
Так это выглядит, как он работает. Что говорит об этом стандарт? Всегда ли законно «распределять» пустой блок памяти?
От 5.3.4/7
Когда значение выражения в прямом-новой-описателя равен нулю, то функция распределения называется выделить массив без элементов.
От 3.7.3.1/2
Эффект разыменования указателя возвращенного как запрос нулевого размера не определен.
Также
Даже если размер запрашиваемого [новыми] пространства равна нулю, то запрос может потерпеть неудачу.
Это означает, что вы можете сделать это, но вы не можете легально (в хорошо определенным образом на всех платформах) разыменовывания памяти, что вы получаете - вы можете только передать его в массив удалить - и вы должны удалить его.
Вот интересная сноска (т.е. не является нормативной частью стандарта, но включен в пояснительных целях) прилагается к предложению от 3.7.3.1/2
[32. Цель состоит в том, чтобы реализовать оператор new(), вызвав malloc() или calloc(), поэтому правила в основном одинаковы. C++ отличается от C требуя нулевой запрос вернуть непустой указатель.]
+1 для цитирования стандарта! – Nav
Я получаю утечку памяти, если не удаляю. Ожидается? По крайней мере, я этого не ожидал. – EralpB
@ EralpB: наоборот, даже если ваш запрос равен нулю, это распределение происходит в куче, где один запрос подразумевает несколько операций с книгами, таких как выделение и инициализация кучи памяти до и после зоны, заданной распределителем, вставка в фриланс или других сложных ужасных структур. Освобождение это означает делать обратную бухгалтерскую отчетность. –
Да, это законно выделять массив нулевого размера, подобный этому. Но вы также должны удалить его.
У вас есть цитата для этого? Мы все знаем, что 'int ar [0];' является незаконным, почему новый ОК? – Motti
См. Ответ Фейсала. – 2009-07-06 13:48:17
Интересно, что C++ не настолько силен с запретом объектов с нулевым размером. Подумайте о пустой оптимизации базового класса: здесь тоже может быть нулевой размер объекта подпункта пустого базового класса. Напротив, C-стандарт прилагает все усилия, чтобы гарантировать, что никогда не создаются объекты с нулевым размером: при определении malloc (0) он говорит, что эффект заключается в запуске malloc с некоторым ненулевым аргументом. И в struct {...; T n []; }; когда нет свободного пространства для массива (FAM), он говорит, что он ведет себя так, как будто «n» имеет один элемент. (В обоих случаях использование объекта каким-либо образом является UB, например, x.n [0]) –
Да, это вполне законно выделить размерный блок в 0
с new
. Вы просто ничего не можете с ним поделать, поскольку для доступа к ним нет действительных данных. int[0] = 5;
является незаконным.
Тем не менее, я считаю, что стандарт позволяет такие вещи, как malloc(0)
, вернуть NULL
.
Вам все равно потребуется delete []
любой указатель, который вы получите обратно из распределения.
Что касается malloc, вы правы - это реализация определена. Это часто рассматривается как неисправность. – 2009-07-06 13:49:31
Я полагаю, интересный вопрос: может ли новая версия нового возврата NULL при заданном размере 0? –
Семантика новых и malloc никоим образом не связана, по крайней мере, стандартом. – 2009-07-06 13:53:50
Что говорит об этом стандарт? Всегда ли законно «распределять» пустой блок памяти?
Каждый объект имеет уникальный идентификатор, то есть уникальный адрес, который подразумевает ненулевую длину (фактический объем памяти будет постепенно увеличиваться, если вы запрашиваете нулевые байты).
Если вы выделили более одного из этих объектов, вы обнаружите, что у них разные адреса.
«Каждый объект имеет уникальный идентификатор, то есть уникальный адрес, который подразумевает ненулевую длину» - true, но неправильно. Объект имеет адрес, но указатель на объект может указывать на случайную память. «Фактический объем памяти будет бесшумно увеличен, если вы попросите нулевые байты» - не уверен. 'operator []' также хранит размер массива где-нибудь (см. https://isocpp.org/wiki/faq/freestore-mgmt#num-elems-in-new-array). Поэтому, если реализация выделяет счетчик байтов с данными, он может просто выделить для байта счет и 0 байтов для данных, возвращая 1-последний-последний указатель. – Steed
Ненулевая длина выделенной памяти, а не ненулевая длина полезной памяти. Я хотел сказать, что два указателя на два разных объекта не должны указывать на один и тот же адрес. – ChrisW
Стандарт (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf) действительно говорит (3.7.4.1/2), что разные вызовы 'operator new [ ] 'должен возвращать разные указатели. BTW, в «новом выражении» есть некоторые дополнительные правила (5.3.4). Я не мог найти подсказки, что 'new' с 0 размером на самом деле _required_, чтобы выделить что-либо. Извините, я отказался, потому что считаю, что ваш ответ не отвечает на вопросы, но дает некоторые противоречивые утверждения. – Steed
Любопытно, что C++ требует, чтобы оператор new возвращал законный указатель , даже когда запрашивались нулевые байты. (. Требуя это нечетное звучащий поведение упрощает вещи в другом месте на языке)
Я нашел Эффективное использование C++ Третье издание сказал, как это в «Пункт 51: Придерживайтесь конвенции при написании новых и удаление».
+1 Очень интересный вопрос - хотя я не уверен, насколько это важно в реальном коде. – Zifre
@ Zifre: Я прошу любопытства, но это может иметь значение в реальном мире, например. когда размер выделенных блоков памяти вычисляется каким-то образом, и результат вычисления может быть равен нулю, тогда нет прямой необходимости добавлять исключения, чтобы не выделять блоки нулевого размера. Потому что они должны быть выделены и удалены без ошибок (если только блок с нулевым размером не разыменован). Как правило, это дает более широкую абстракцию того, что представляет собой блок памяти. – 2009-07-06 13:59:35
@ emg-2: В вашем примере ситуация на самом деле не имеет значения, потому что delete [] совершенно легально по указателю NULL :-). –