Подтвердить что ты не робот

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

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

4b9b3361

Ответ 1

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

Ответ 2

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

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

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

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

Ответ 3

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

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

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

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

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

Безопасный способ очистки кода будет состоять в следующем: set_new_handler.

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

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

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

Стандартный заголовочный файл С++ определяет 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];

Вот хорошее подтверждение для дальнейшего чтения