Что такое стандартное поведение C ++ для new
в c ++?
Обычно считается, что если оператор new
не может выделить динамическую память запрошенного размера, он должен вызвать исключение типаstd::bad_alloc
.
Однако что-то еще происходит еще до того, как выдается исключение bad_alloc
:
C ++ 03 Раздел 3.7.4.1.3: говорит
Функция выделения, которая не выделяет хранилище, может вызывать установленный в данный момент new_handler (18.4.2.2), если таковой имеется.[Примечание: предоставляемая программой функция выделения может получить адрес установленного в данный момент new_handler, используя функцию set_new_handler (18.4.2.3).] Если функция выделения объявлена с пустой спецификацией исключений (15.4), throw () завершается неудачновыделить память, он должен вернуть нулевой указатель.Любая другая функция выделения, которая не может выделить хранилище, должна указывать на сбой только путем генерирования исключения класса std :: bad_alloc (18.4.2.1) или класса, производного от std :: bad_alloc.
Рассмотримследующий пример кода:
#include <iostream>
#include <cstdlib>
// function to call if operator new can't allocate enough memory or error arises
void outOfMemHandler()
{
std::cerr << "Unable to satisfy request for memory\n";
std::abort();
}
int main()
{
//set the new_handler
std::set_new_handler(outOfMemHandler);
//Request huge memory size, that will cause ::operator new to fail
int *pBigDataArray = new int[100000000L];
return 0;
}
В приведенном выше примере operator new
(наиболее вероятно) не сможет выделить место для 100 000 000 целых чисел, и будет вызвана функция outOfMemHandler()
, и программапрерывание после выдачи сообщения об ошибке.
Как видно из приведенного здесь поведения по умолчанию оператора new
, когда не удается выполнить запрос памяти, является повторный вызов функции new-handler
, пока она не сможетнайти достаточно памяти или больше нет новых обработчиков.В приведенном выше примере, если мы не вызовем std::abort()
, outOfMemHandler()
будет , который будет вызываться повторно .Следовательно, обработчик должен либо гарантировать, что следующее выделение выполнено успешно, либо зарегистрировать другой обработчик, либо не регистрировать обработчик, либо не возвращать (то есть завершать программу).Если нового обработчика нет и распределение завершается неудачно, оператор выдаст исключение.
Что такое new_handler
и set_new_handler
?
new_handler
- это typedef для указателядля функции, которая ничего не принимает и не возвращает, а set_new_handler
- это функция, которая принимает и возвращает new_handler
.
Что-то вроде:
typedef void (*new_handler)();
new_handler set_new_handler(new_handler p) throw();
Параметр set_new_handler - указатель на функцию, которую должен вызывать оператор new
, если он не может выделить запрошенную память.Его возвращаемое значение - указатель на ранее зарегистрированную функцию-обработчик, или ноль, если не было предыдущего обработчика.
Как обрабатывать нехватку памяти в C ++?
Учитывая поведение new
хорошо разработанная пользовательская программа должна обрабатывать нехватку памяти, предоставляя правильное значение new_handler
, которое выполняет одно из следующих действий:
Сделать больше памяти доступным: Это может позволить следующее выделение памятипопытка внутри цикла оператора new завершиться успешно.Одним из способов реализации этого является выделение большого блока памяти при запуске программы, а затем освобождение его для использования в программе при первом вызове нового обработчика.
Установка другого нового-handler: Если текущий новый обработчик не может сделать больше доступной памяти, и если есть другой новый обработчик, который может, то текущий новый обработчик может установить другой новый обработчик на свое место (с помощьюзвонит set_new_handler
).В следующий раз, когда оператор new вызывает функцию new-handler, он получит последнюю установленную функцию.
(Разновидностью этой темы является то, что new-handler изменяет свое поведение, поэтому в следующий развызывается что-то другое. Один из способов добиться этого - заставить новый обработчик изменять статические, специфичные для пространства имен или глобальные данные, которые влияют на поведение нового обработчика.)
Удалите новый-handler: Это делается путем передачи нулевого указателя на set_new_handler
.Если не установлен новый обработчик, operator new
будет выдавать исключение ((преобразуемое в) std::bad_alloc
), если выделение памяти окажется неудачным.
Бросить исключение , преобразуемое в std::bad_alloc
.Такие исключения не будут перехвачены operator new
, но будут распространяться на сайт, инициирующий запрос памяти.
Не возвращается: Позвонив по номеру abort
или exit
.