Вопрос

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

Это было полезно?

Решение

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

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

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

Кажется, что МС это почистил в версии 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, когда вы используете просто новый код без параметров, но, конечно, могут быть некоторые несовместимые компиляторы.

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

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

При этом вот несколько вариантов очистки вашего кода:

Опция 1:Установка собственного нового обработчика

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

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

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

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

Стандартный заголовочный файл C++ определяет пустую структуру.Вы можете использовать объект этой структуры внутри 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];

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top