2009-02-15 2 views
44

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

ответ

48

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

Вот KB Article Microsoft по этому вопросу вместе с их предложил обходной путь с помощью настраиваемого new обработчика:

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

Кажется, что MS cleaned this up в 8.0 (VS2005) — теперь он всегда по умолчанию использует метание нового, если вы не ссылаетесь на nothrownew.obj.

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

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

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

+0

Неверные номера версий. Это было нарушено в 5.0 (как говорится в статье, на которую вы ссылаетесь). Это было исправлено в 6.0. –

+0

VC6 по умолчанию также возвращает NULL - я только что протестировал его. Согласно ссылкам «kftdy56f», поведение в VC7 и VC7.1 (VS2002 и VS2003) также может возвращать NULL, в зависимости от того, была ли ссылка libc * .lib или libcp * .lib (CRT или стандартная библиотека C++) в Я не заинтересован в тестировании. –

+5

Чтобы быть справедливым, VC6 был выпущен до того, как был утвержден стандарт C++, что является одной из причин, по которым оно было настолько несоответствующим.Это правда, что стандарт был почти закончен в то время, но нужно помнить, что существуют циклы разработки, и VC6, вероятно, начался по крайней мере годом ранее. –

8

Основываясь на спецификации 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]; 

Вот a good refrence for further reading

+1

Насколько я понимаю, установка NULL после удаления. Но моя проблема заключается в следующем: int * p = new int; if (p == NULL) { // журнал о сбое распределения памяти. return; } – Naveen

+0

gotcha, обновлено. –

+0

Вы можете бросить bad_alloc в свой новый обработчик, но нет ничего, чтобы проверить NULL. Вы также не можете изменить возвращаемое значение new через обработчик. – 2009-02-15 08:03:11

19

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

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

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

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

+4

«Код завершен» предлагает предварительно выделить «защитную сетку» памяти, которая может использоваться при работе в ситуациях с нехваткой памяти, чтобы можно было, например, сохранить информацию об отладке до выхода. –

+3

Проблема в том, что на современной VM-системе, если вы придете где-нибудь _near_, закончите (виртуальную) память, вещь будет пейджинговой, так что она будет полностью непригодна. – 2009-02-15 09:58:41

+0

Stefan, zabzonk: больше не могу согласиться. – 2009-02-15 10:30:43

Смежные вопросы