Будет ли новый вернуть NULL в любом случае?

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

3 ответа

Решение

В этом отношении 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, так что это может быть способ более или менее механически исправить код, чтобы он работал одинаково со всеми компиляторами, чтобы вам не пришлось переделывать существующую обработку ошибок.

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

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

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

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

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

Я бы не стал кодировать для совместимости с компиляторами, не совместимыми с 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];

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

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