Никогда не аннотировать функции, связанные с динамическим выделением памяти, как noexcept?

Предположим, у вас есть функция, которая обычно никогда не подведет, например:

std::string convert_integer_to_string(int x);

в принципе, это был бы кандидат на noexcept. Однако реализация, скорее всего, включает в себя динамическое управление памятью, поэтому она всегда может бросить std:: bad_alloc при выделении памяти с помощью тега new оператора.

рекомендуется ли аннотировать функцию как noexcept?

С практической точки вид, это чрезвычайно трудно обрабатывать ситуации из памяти разумным образом. Большинство программ просто предполагают, что доступно достаточно памяти. Зову std::terminate, как это произошло бы, если бы

2 ответов


если функция может вызвать исключение по какой-либо причине, даже если это std::bad_alloc вы должны не объявил его как noexcept. Есть относительно мало функций, которые действительно не могут выдать исключение и где это на самом деле также имеет значение. Первичная потребность в noexcept функции позволяют обнаруживать доступные параметры восстановления ошибок в случае исключения: например,std::vector<T, A> может использовать конструкцию перемещения при вставке объекта, предполагая, что конструкция перемещения не бросает. Если конструкция move может вызывать, движущиеся объекты нельзя использовать для восстановления исключения при реализации безопасных операций строгого исключения. Таким образом, если move construction может потерпеть неудачу для типа T экземпляр std::vector<T, A> невозможно перемещать объекты, но их необходимо скопировать.

в частности,не использовать noexcept как ложная документация:это нарушение контракта, если функция действительно может бросить. Дело в том, что система реагирует с некоторым уровнем определенное поведение в случае этого нарушения не означает, что вы должны воспользоваться им. ... и хотя простые программы, вероятно, не восстановятся и просто умрут при запуске памяти, реальным программам может потребоваться, по крайней мере, сохранить достаточное состояние для восстановления беспорядка, который они оставляют после себя при умирании, т. е. для любой функции неприемлемо принимать решение об убийстве программы (если, конечно, это не задокументировано намерением функции).


Я не уверен,что буду беспокоиться об исключениях из памяти.

в некоторых ОС (по крайней мере, linux) поведение по умолчанию, когда у вас заканчивается память, должно быть убито ОС (убийца ООТ). Это происходит, когда вы пишете в память (а не когда вы ее выделяете), и вам не будет предоставлена возможность запустить код очистки. Эта функция называется память overcommit

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

обратите внимание, что вы также можете использовать std:: nothrow чтобы проверить результат распределения без использования исключений (то есть, предоставление вашей ОС фактически сообщает вам эту информацию во время распределения). Возможно, имеет смысл сделать это, когда вы делаете большое распределение, которое, по вашему мнению, может потерпеть неудачу. Это также имеет хорошее свойство, что вместо того, чтобы иметь дело с (потенциально) необработанными исключениями, вы получите nullptr, который будет довольно легко отлаживать.