Будет ли new возвращать NULL в любом случае?

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

3 ответов


VC6 был по умолчанию несовместим в этом отношении. вернулся 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 С помощью :

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

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


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

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

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

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


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

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

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

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

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

безопасным способом очистки кода будет вызов:set_new_handler первый.

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

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

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

стандартный файл заголовка c++ определяет пустую структуру 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];

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