Есть ли что-нибудь новенькое, ожидающее, пока освободится память?

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

См. Этот пример в принятом ответе на этот вопрос:

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. в блок попытки и обработать исключения здесь (и pop_back список). Тогда функция обеспечит гарантию отсутствия перетаскивания, и в списке всегда будут хорошие вещи.

Пользователям будет наплевать на разницу между 100% ЦП и 100% ОЗУ. Когда они видят, что программа зависает, они закрывают другие программы, поэтому new находит достаточно памяти и продолжает работу.

Мой вопрос: можно ли это реализовать? Есть ли что-нибудь новенькое, ожидающее, пока освободится память? Могу ли я применить его глобально (например, #define new ...), чтобы библиотеки до стандартизации C ++ могли выжить во временном 100% ОЗУ?


person jingyu9575    schedule 03.12.2013    source источник
comment
Проверка работоспособности: что, если он попытается использовать new 100 ТБ памяти, когда у вас всего 4 ГБ? Вы ждете вечно?   -  person Mysticial    schedule 03.12.2013
comment
Возможным решением может быть новое ожидание, пока не станет доступной память - не будет работать в однопоточном сценарии. А также std::bad_alloc и 100% RAM usage абсолютно не связаны.   -  person Joker_vD    schedule 03.12.2013
comment
Что за? Когда пользователь видит, что ваша программа зависает, он не закрывает другие программы. Они закрывают твое.   -  person chris    schedule 03.12.2013
comment
@Mysticial: значит программа несовместима с оборудованием или x86. Бесконечное ожидание и разрешение пользователю выполнить принудительное закрытие ничем не отличается от демонстрации того, что ваша машина слишком старая, и принудительного закрытия.   -  person jingyu9575    schedule 03.12.2013
comment
@chris - выбор пользователя. Если вы обнаружите, что ваша дота начинает отставать, вы закрываете игру или другие службы? Я часто открываю много других программ при копировании больших файлов, и если процесс копирования зависает, я лучше перестану читать веб-страницы, чем сделаю копию файла наполовину и попытаюсь исправить это позже.   -  person jingyu9575    schedule 03.12.2013
comment
@Joker_vD в однопоточном сценарии я могу использовать значение по умолчанию new. Интересно, есть ли способ позволить моей программе немного подождать, вместо того, чтобы прерывать операцию, когда я внезапно открываю много веб-страниц.   -  person jingyu9575    schedule 03.12.2013
comment
@ jingyu9575 Исключение std::bad_alloc вызвано исчерпанием адресного пространства вашей программы, а не ограничениями физической памяти. Вы можете выделить new std::vector<char>(1024 * 1024 * 1024, 'x') на машине с 256 МБ ОЗУ, и она не будет сброшена и будет работать нормально (если будет медленно).   -  person Joker_vD    schedule 03.12.2013
comment
@Joker_vD Почему? Если у меня нет файлов подкачки на дисках, где хранятся символы 'x'?   -  person jingyu9575    schedule 03.12.2013
comment
@Joker_vD auto* p = new std::vector<char>((std::vector<char>::size_type)(10.0 * 1024 * 1024 * 1024), 'x'); выдает std::bad_alloc, когда я выключаю виртуальную память в Windows 8.1 с физической памятью 4 ГБ. Если я установил для виртуальной памяти значение auto, вы правы, она работает, но работает медленно (100% дискового ввода-вывода). x64 сборка.   -  person jingyu9575    schedule 03.12.2013


Ответы (1)


Это сомнительный дизайн, но вы, безусловно, можете сделать это с помощью «нового обработчика». Новый обработчик по умолчанию просто выбрасывает std::bad_alloc. Если новый обработчик вернется, new зациклится и попытается выделить снова. Он также используется оператором nothrow new, но std::bad_alloc, брошенный обработчиком new, в этом случае перехватывается и возвращается NULL.

Вам просто нужно установить новый обработчик для своей пользовательской функции void (*)() обработчика . По крайней мере, вы можете захотеть на время приостановить процесс, скажем, на 1/10 секунды. Опять же, в любом случае продолжение программы может оказаться невозможным - например, в Linux есть «убийца OOM», который может быть настроен администратором.

person Brett Hale    schedule 03.12.2013
comment
IIRC, в Linux std::bad_alloc почти никогда не выкидывается из-за функции избыточной фиксации. - person Joker_vD; 03.12.2013
comment
какие-либо указатели на то, как повторить попытку распределения? Я сейчас на: void outOfMemHandler() { std::cerr << "Out of memory, I'm just going to sleep for a while."<<endl; sleep(10); // if success : break // if fail : retry 100 times //throw (std::bad_alloc); > 100 //std::abort(); } - person Stefan Rogin; 18.10.2014