Может ли оператор C ++ `new` когда-либо генерировать исключение в реальной жизни? - PullRequest
43 голосов
/ 23 марта 2010

Может ли оператор new вызвать исключение в реальной жизни?

И если да, есть ли у меня какие-либо варианты обработки такого исключения, кроме как убить мое приложение?

Обновление:

Проверяют ли какие-либо приложения, работающие в реальных условиях, new с высокой нагрузкой, на наличие сбоев и восстанавливаются ли при отсутствии памяти?


Смотри также:

Ответы [ 18 ]

3 голосов
/ 24 марта 2010

Обратите внимание, что в Windows очень большие новые / mallocs будут просто выделяться из виртуальной памяти.На практике ваша машина зависнет до того, как вы увидите это исключение.

char *pCrashMyMachine = new char[TWO_GIGABYTES];

Попробуйте, если решитесь!

2 голосов
/ 23 марта 2010

Я использую Mac OS X, и я никогда не видел, чтобы malloc возвращало NULL (что означало бы исключение из new в C ++).Машина останавливается, делает все возможное, чтобы распределить сокращающуюся память для процессов, и, наконец, отправляет SIGSTOP и предлагает пользователю уничтожать процессы, а не заставлять их справляться с ошибкой выделения.ВНИМАТЕЛЬНО есть платформы, на которых распределитель по умолчанию работает.И, как говорит Крис, ulimit может вводить искусственное ограничение, так что ожидаемым поведением будет исключение.

Кроме того, существуют распределители помимо значения по умолчанию / malloc.Если класс переопределяет operator new, вы используете пользовательские аргументы для new(…) или передаете объект-распределитель в контейнер, он, вероятно, определяет свои собственные условия для выброса bad_alloc.

1 голос
/ 02 октября 2013

Хорошо проверять / перехватывать это исключение, когда вы выделяете память на основе чего-то, данного извне (из пользовательского пространства, сети, например), потому что это может означать попытку поставить под угрозу ваше приложение / услугу / систему, и вы не должны позвольте этому случиться.

1 голос
/ 02 октября 2013

Функция нового обработчика - это функция, вызываемая функциями выделения всякий раз, когда новая попытка выделения памяти завершается неудачей.У нас может быть свое собственное ведение журнала или какое-то специальное действие, например, g подготовка большего количества памяти и т. Д. Его предназначение - одна из трех вещей: 1) сделать больше доступной памяти 2) завершить программу (например, вызвав std :: terminate)) сгенерировать исключение типа std :: bad_alloc или производного от std :: bad_alloc.Реализация по умолчанию выбрасывает std :: bad_alloc.Пользователь может иметь свой собственный новый обработчик, который может предлагать поведение, отличное от поведения по умолчанию.Это следует использовать только тогда, когда вам действительно нужно.См. Пример для получения дополнительной информации и поведения по умолчанию,

#include <iostream>
#include <new>

void handler()
{
    std::cout << "Memory allocation failed, terminating\n";
    std::set_new_handler(nullptr);
}

int main()
{
    std::set_new_handler(handler);
    try {
        while (true) {
            new int[100000000ul];
        }
    } catch (const std::bad_alloc& e) {
        std::cout << e.what() << '\n';
    }
}
1 голос
/ 23 марта 2010

Оператор new выдаст исключение std :: bad_alloc, если в пуле недостаточно доступной памяти для выполнения запроса времени выполнения.

Это может произойти при плохом дизайне или когда выделенная память не освобождается правильно.

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

1 голос
/ 23 марта 2010

Да, новый может и скинет.

Поскольку вы спрашиваете о «настоящих» программах: я работаю над различными коммерческими приложениями в термоусадочной пленке более 20 лет. «Реальные» программы с миллионами пользователей. Это вы можете пойти и купить с полки сегодня. Да, новый может бросить.

Существуют различные способы справиться с этим.

Сначала напишите свой собственный new_handler (он вызывается до того, как new сдается и бросает - см. Функцию set_new_handler ()). Когда ваш new_handler вызывается, посмотрите, сможете ли вы освободить некоторые вещи, которые вам на самом деле не нужны. Также предупредите пользователя, что ему не хватает памяти. (да, может быть сложно предупредить пользователя о чем-либо, если вы действительно низкий).

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

Etc. Это просто обзор, очевидно, это еще не все.

Работать с малым объемом памяти непросто.

1 голос
/ 23 марта 2010

Большинство реально новых бросков из-за решения об ограничении ресурса.Скажем, этот класс (который может занимать много памяти) забирает память из пула физических данных, и если многим объектам брать из него (нам нужна память для других вещей, таких как звук, текстуры и т. Д.), Он может выбрасываться, а не падать позже, когда что-тобыть в состоянии выделить память занимает это.(выглядит как странный побочный эффект).

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

0 голосов
/ 23 марта 2010
Оператор

new выдаст исключение std::bad_alloc, когда вы исчерпаете память (точнее, виртуальную память).

Если new выдает исключение, то это серьезная ошибка:

  • Распределяется больше доступной виртуальной машины (в конечном итоге происходит сбой). Вы можете попытаться уменьшить объем памяти, чем выход из программы, перехватывая исключение std::bad_alloc.
...