Будет ли новый вернуть NULL в любом случае? - PullRequest
51 голосов
/ 15 февраля 2009

Я знаю, что в соответствии со стандартом C ++ в случае, если new не выделяет память, он должен выдать исключение std :: bad_alloc Но я слышал, что некоторые компиляторы, такие как VC6 (или реализация CRT?), Не придерживаются этого. Это правда ? Я спрашиваю об этом, потому что проверка на NULL после каждого нового оператора делает код очень уродливым.

Ответы [ 3 ]

54 голосов
/ 15 февраля 2009

VC6 по умолчанию не соответствует требованиям. VC6 new вернул 0 (или NULL).

Вот статья Microsoft KB по этому вопросу, а также предлагаемый обходной путь с использованием специального обработчика new:

Если у вас есть старый код, который был написан для поведения VC6, вы можете получить то же поведение с более новыми компиляторами MSVC (что-то вроде 7.0 и более поздних версий), связавшись с объектным файлом с именем nothrownew.obj. На самом деле довольно сложный набор правил в компиляторах 7.0 и 7.1 (VS2002 и VS2003), чтобы определить, по умолчанию они не бросали или бросали new.

Похоже, что MS исправила это в 8.0 (VS2005) - теперь он всегда по умолчанию выбрасывает новый, если вы специально не ссылаетесь на nothrownew.obj.

Обратите внимание, что вы можете указать, что вы хотите, чтобы new возвращал 0 вместо броска std::bad_alloc с использованием параметра std::nothrow:

SomeType *p = new(std::nothrow) SomeType;

Это похоже на работу в VC6, так что это может быть способ более или менее механически исправить код, чтобы он работал одинаково со всеми компиляторами, чтобы вам не пришлось переделывать существующую обработку ошибок.

19 голосов
/ 15 февраля 2009

Я хотел бы добавить несколько (спорное) мнение, что проверка на NULL после попытки выделения в значительной степени упражнения в бесполезности. Если ваша программа когда-либо сталкивается с такой ситуацией, скорее всего, вы не можете сделать гораздо больше, чем быстро выйти. Весьма вероятно, что любая последующая попытка выделения также не удалась.

Без проверки на NULL ваш последующий код будет пытаться разыменовать указатель NULL, который имеет тенденцию быстро выходить из программы, с относительно уникальным (и легко отлаживаемым) условием выхода.

Я не пытаюсь отговорить вас от проверки на NULL, это, безусловно, добросовестное программирование. Но от этого вы мало что выиграете, если только в очень специфических случаях вы, возможно, не сможете сохранить некоторую информацию для восстановления (без выделения дополнительной памяти) или освободить менее важную память и т. Д. Но эти случаи будут относительно редки для большинства людей.

Учитывая это, я бы просто доверил компилятору лично сгенерировать bad_alloc - по крайней мере, в большинстве случаев.

9 голосов
/ 15 февраля 2009

Исходя из спецификации C ++, он всегда будет выдавать std :: bad_alloc, когда вы используете просто новый, без параметров, но, конечно, могут быть некоторые несовместимые компиляторы.

Я бы не стал кодировать для совместимости с компиляторами, не совместимыми с c ++. VC6 является одним из них в этом отношении.

Рекомендуется всегда устанавливать указатель на NULL после их удаления. Поэтому из-за этого проверка на NULL все еще необходима.

Как говорится, вот несколько вариантов очистки вашего кода:

Вариант 1: установка собственного нового обработчика

Безопасный способ очистить ваш код - это сначала позвонить: set_new_handler .

Тогда вы можете проверить NULL в вашем обработчике и бросить туда std :: bad_alloc, если возвращается NULL.

Если вам больше нравятся исключения, тогда это ваш лучший выбор. Если вам нравится возвращать NULL лучше, вы также можете сделать это, выполнив перехват в вашем новом обработчике.

Вариант 2: использование перегруженного нового

Стандартный заголовочный файл c ++ определяет struct nothrow, которая является пустой. Вы можете использовать объект этой структуры внутри new, чтобы получить его перегруженную версию, которая всегда возвращает NULL.

void* operator new (size_t size, const std::nothrow_t &);
void* operator new[] (void *v, const std::nothrow_t &nt);

Так в вашем коде:

 char *p = new(std::nothrow) char[1024];

Вот хорошая ссылка для дальнейшего чтения

...