Перед чтением этот вопрос, Я никогда не относился к обработке исключений серьезно. Теперь я вижу необходимость, но все еще чувствую, что «написание безопасного кода исключений очень сложно».
Посмотрите этот пример в принятом ответе на этот вопрос:
void doSomething(T & t)
{
if(std::numeric_limits<int>::max() > t.integer) // 1. nothrow/nofail
t.integer += 1 ; // 1'. nothrow/nofail
X * x = new X() ; // 2. basic : can throw with new and X constructor
t.list.push_back(x) ; // 3. strong : can throw
x->doSomethingThatCanThrow() ; // 4. basic : can throw
}
Как говорится в ответе, я легко могу предложить основную гарантию, используя std::unique_ptr
, Однако, когда я ловлю std::bad_alloc
Я не знаю, происходит ли это в push_back
или же x->doSomethingThatCanThrow()
, поэтому я не могу знать, является ли t.list все еще «хорошим» или его последний элемент не полностью подготовлен. Тогда единственный выбор — сбросить t, показать страшное сообщение и прервать его, если t необходимо для всей программы.
Код с сильной гарантией не имеет проблемы, но «он может стать дорогостоящим» (в этом примере используется копия большого списка) и не так удобочитаем.
Возможное решение может быть принятие new
дождитесь освобождения памяти, удалив самое раздражающее исключение std::bad_alloc
, Тогда 2. и 3. не будет бросать (при условии X
Строительство и копирование всегда удаются). Я могу просто обернуть 4. в блок try и иметь дело с исключениями здесь (и pop_back список). Тогда функция обеспечит nothrow гарантией, а список всегда будет содержать хорошие вещи.
Пользователи не будут заботиться о разнице между 100% CPU и 100% RAM. Когда они видят зависание программы, они закрывают другие программы так, new
находит достаточно памяти и продолжает.
Мой вопрос: это можно реализовать? Есть ли что-нибудь новое, что ждет, пока не освободится память? Могу ли я применить его глобально (например, #define new ...
) поэтому библиотеки до стандартизации C ++ могут пережить временную 100% оперативную память?
Это сомнительный дизайн, но вы, безусловно, можете сделать это с помощью «нового обработчика». Новый обработчик по умолчанию просто выбрасывает std::bad_alloc
, Если новый обработчик возвращается, new
будет цикл, и попытаться выделить снова. Он также используется оператором nothrow new, но std::bad_alloc
брошенный новым обработчиком пойман, и NULL
вернулся, в таком случае.
Вам просто нужно задавать новый обработчик на ваш заказ void (*)()
функция обработчика. По крайней мере, вы можете захотеть уложить процесс на некоторое время — скажем, 1/10 сек. Опять же, в любом случае, программа не сможет продолжить работу — например, в Linux есть «убийца OOM», который может быть настроен администратором.
Других решений пока нет …