Политика с отловом std :: bad_alloc - PullRequest
12 голосов
/ 20 августа 2009

Так что я часто использую Qt в своей разработке и мне это нравится. Обычный шаблон проектирования с объектами Qt состоит в том, чтобы выделить их, используя new.

Практически все примеры (особенно код, сгенерированный конструктором Qt) абсолютно не проверяют исключение std::bad_alloc. Поскольку выделенные объекты (обычно виджеты и тому подобное) малы, это вряд ли когда-либо проблема В конце концов, если вам не удастся выделить что-то вроде 20 байтов, скорее всего, вы ничего не сможете сделать, чтобы устранить проблему.

В настоящее время я принял политику оборачивания "больших" (что-либо больше, чем страница или два размера) выделений в try / catch. Если это не удается, я отображаю сообщение пользователю, в значительной степени меньше, я просто позволю приложению аварийно завершить работу с исключением std::bad_alloc.

Итак, мне интересно, что это за мысли об этом?

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

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

Ответы [ 6 ]

17 голосов
/ 20 августа 2009

Проблема не в том, «где ловить», а в том, «что делать, когда ловится исключение».

Если вы хотите проверить, вместо try catch лучше использовать

    #include <new>
    x = new (std::nothrow) X();
    if (x == NULL) {
        // allocation failed
    }

Моя обычная практика

  • в неинтерактивной программе, перехватить на главном уровне и отобразить там соответствующее сообщение об ошибке.

  • в программе, имеющей цикл взаимодействия с пользователем, перехватывайте также в цикле, чтобы пользователь мог закрыть некоторые вещи и попытаться продолжить.

Исключительно, есть и другие места, где улов имеет смысл, но это редко.

11 голосов
/ 20 августа 2009

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

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

6 голосов
/ 20 августа 2009

Я обычно ловлю исключения в момент, когда пользователь инициировал действие. Для консольного приложения это означает main, для приложений с графическим интерфейсом я помещаю обработчики в такие места, как обработчики нажатия кнопок и т. Д.

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

4 голосов
/ 04 января 2012

Это относительно старый поток, но он возник, когда я искал соображения "std :: bad_alloc" при выполнении переопределения new / delete в 2012 году.

Я бы не воспринял концепцию «ну, ничего, что вы можете сделать в любом случае» как жизнеспособный вариант. Я лично использую в своих собственных распределениях "if (alloc ()) {} else {error / processing}", упомянутый выше. Таким образом, я могу правильно обрабатывать и, или, сообщать о каждом случае в их собственном значимом контексте.

Теперь, некоторые другие возможные решения: 1) Переопределите новый / удалить для приложения, где вы можете добавить свой собственный из нехватки памяти.

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

Здесь вы могли бы, по крайней мере, всплыть диалоговое окно и сказать что-то вроде: "Приложению не хватило памяти. Это фатальная ошибка, и теперь она должна завершиться самостоятельно. Приложение должно быть запущено с минимальными требованиями к системной памяти. Отправлять отчеты об отладке в xxxx ". Обработчик также может сохранить любую незавершенную работу и т. Д., Подгоняя приложение.

В любом случае вы не захотите использовать это для чего-то критического (например, предупреждение, любительский юмор впереди): космический челнок, монитор сердечного ритма, аппарат для диализа почек и т. Д. Конечно, эти вещи требуют гораздо более надежных решений, использующих отказоустойчивые сейфы, методы аварийной сборки мусора, 100% тестирование / отладка / фаззинг и т. Д.

2) Как и в первом случае, установите глобальный set_new_handler () с вашим собственным обработчиком, чтобы перехватить состояние нехватки памяти в глобальной области видимости. Может по крайней мере справиться с вещами, как упоминается в # 1.

1 голос
/ 08 августа 2012

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

0 голосов
/ 21 августа 2009

Обработайте его в main() (или эквивалентном обработчике исключений верхнего уровня в Qt)

Причина в том, что std :: bad_alloc происходит, когда вы исчерпываете пространство памяти (2 или 3 ГБ в 32-битных системах, не происходит в 64-битных системах) или когда вы исчерпываете пространство подкачки. Современные распределители кучи не настроены на запуск из пространства подкачки, поэтому это будет медленная, шумная смерть - есть вероятность, что ваши пользователи забьют ваше приложение заранее, поскольку его пользовательский интерфейс больше не отвечает. А в Linux обработка памяти ОС по умолчанию настолько плоха, что ваше приложение может быть автоматически убито.

Итак, вы мало что можете сделать. Признайтесь, что у вас есть ошибка, и посмотрите, сможете ли вы сохранить любую работу, которую мог выполнить пользователь. Чтобы иметь возможность сделать это, лучше всего прервать как можно больше. Да, это может на самом деле потерять часть последнего пользовательского ввода. Но это именно то действие, которое, вероятно, спровоцировало ситуацию с OOM. Цель - сохранить любые данные, которым вы можете доверять.

...