Дополнительно
Как справиться с bad_alloc в C++?
Существует метод foo
, который иногда возвращает следующую ошибку:
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Abort
Есть ли способ использовать блок try
-catch
, чтобы остановить эту ошибку от завершения моей программы (все, что я хочу сделать, это вернуть -1
)?
Если да, то каков его синтаксис?
Как еще я могу справиться с bad_alloc
в C++?
51
6
В общем случае вы не можете и не должны пытаться реагировать на эту ошибку.
bad_alloc
указывает на то, что ресурс не может быть выделен, потому что недостаточно памяти. В большинстве сценариев ваша программа не может надеяться справиться с этим, и единственным разумным поведением будет ее скорое завершение.Хуже того, современные операционные системы часто перераспределяют ресурсы: в таких системах
malloc
иnew
могут создать правильный указатель, даже если свободной памяти недостаточно -std::bad_alloc
никогда не будет выброшен, или, по крайней мере, не является надежным признаком исчерпания памяти. Вместо этого, попытки доступа к выделенной памяти приведут к ошибке сегментации, которую невозможно поймать (вы можете обработать сигнал ошибки сегментации, но после этого вы не сможете возобновить работу программы).Единственное, что вы можете сделать, поймав
std::bad_alloc
, это, возможно, записать ошибку в лог и попытаться обеспечить безопасное завершение программы, освободив оставшиеся ресурсы (но это делается автоматически в ходе обычного разворачивания стека после возникновения ошибки, если программа использует RAII должным образом).В некоторых случаях программа может попытаться освободить часть памяти и повторить попытку, или использовать вторичную память (= диск) вместо оперативной памяти, но эти возможности существуют только в очень специфических сценариях с жесткими условиями:
Приложения крайне редко контролируют пункт 1 - приложения пользовательского пространства никогда этого не делают, это общесистемная настройка, для изменения которой требуются права root.1
Хорошо, предположим, что вы исправили пункт 1. Теперь вы можете, например, использовать LRU кэш для некоторых ваших данных (возможно, некоторых особенно больших бизнес-объектов, которые могут быть регенерированы или перезагружены по требованию). Далее, вам нужно поместить фактическую логику, которая может потерпеть неудачу, в функцию, которая поддерживает повторную попытку - другими словами, если она будет прервана, вы можете просто запустить ее заново:
Но даже здесь использование
std::set_new_handler
вместо обработкиstd::bad_alloc
дает ту же пользу и будет намного проще.1 Если вы создаете приложение, которое делает контроль пункта 1, и вы читаете этот ответ, пожалуйста, напишите мне, мне искренне интересно узнать о ваших обстоятельствах.
Что стандарт C++ указанное поведение "новой" в C++?
Обычно считается, что если оператор
new
не могу выделить динамической памяти требуемого размера, он должен сгенерировать исключение типаСТД::bad_alloc
. Однако происходит нечто большее, еще доbad_alloc
исключение:Раздел C++3.7.4.1.3 03: говорит
Рассмотрим следующий пример кода:
Вы можете поймать его, как любое другое исключение:
Что именно вы можете полезного сделать с этого момента, зависит от вас, но технически это определенно осуществимо.
Я бы не советовал этого делать, поскольку
bad_alloc
означает, что у вас кончилась память. Лучше просто сдаться, а не пытаться восстановить память. Однако вот решение, о котором вы спрашиваете:Я могу предложить более простой (и даже быстрее) решение для этого. оператор
new
будет возвращать null, если не удалось выделить память.Я надеюсь, что это может помочь!
Пусть ваш ФОО программы Выход контролируемым образом:
Затем написать программная оболочка, что вызывает реальную программу. Поскольку адресные пространства разделены, состояние вашего программной оболочке всегда хорошо выражен.