tgoop.com/cxx95/80
Last Update:
#story
Чем исключения в C++ похожи на сборщик мусора в других языках ♻️
Имеется в виду не техническая похожесть, а сам принцип наличия фичи. Изначально все фичи выглядят как что-то крутое, что есть "из коробки" и можно использовать без задней мысли.
Но когда возникает нужда что-то поправить в этой фиче, то программист замучается глотать пыль, копаясь в технической реализации.
Например, для Java и других языков со сборкой мусора это необходимость разбираться в алгоритмах сборки мусора (mark-and-sweep, etc.), в более хитрой работе с памятью чтобы сборщик собирал меньше мусора ("пул объектов"), понимать нужные настройки чтобы сборщик не фризил программу посередине HTTP-запроса, и так далее. Это все долго и нудно описывается в разных статьях.
В C++ есть подобная история с исключениями. Но здесь требуются еще более нетривиальные познания для полного понимания. Основных проблем две, первая встречается чаще, но вторая более жесткая:
Вместо того, чтобы просто взять и вызвать функцию, которая теоретически может выбросить исключение, приходится делать дополнительный блок кода для обработки потенциального исключения, и переводить исполнение туда в случае исключения (лишняя проверка на КАЖДЫЙ вызов).
Также во многих оптимизациях исключения не участвуют. Например, оптимизация "удаление мертвого кода" считает, что код для обработки исключений нужен всегда, а там по транзитивности нужны и все переменные внутри него, и в итоге все вообще плохо оптимизируется.
Strong Exception Guarantee это гарантия, что если вызвать метод, который вдруг выбросит исключение, то состояние программы будет таким же, как было до вызова метода. Контейнеры по возможности реализуют SEG, и это очень муторно. В моей статье про контейнеры я описывал, когда работает SEG.
void TryAddWidget(std::vector<Widget>& widgets) {В Стандарте есть велосипеды специально для SEG: std::move_if_noexcept.
// выполняем некий код...
Widget w;
try {
widgets.push_back(std::move(w));
} catch (...) {
// поймали исключение...
// ожидаем, что `widgets` остался юзабельным
}
}
В обычных программах сделать нормальный SEG очень сложно. Не работает история о том, что мы приняли запрос, положили из него данные в структуру, что-то записали в базу данных, залогировали, а потом вдруг поймали исключения и надо все вернуть обратно.
Есть понятие гарантии Basic Exception Guarantee, программа продолжает работать, но данные немного поломаны. Например, в примере выше, в зависимости от свойств класса
Widget
, в векторе widgets
могут стереться все элементы после выброса исключения Объяснение сути BEG на примере саппорта Microsoft Word (
Во многих code style (например от Google) исключения использовать запрещено.
В компиляторах есть флаг
-fno-exceptions
, которые удаляют весь оверхед, связанный с исключениями, не генерируют лишний код. Исключения до сих пор можно будет бросать, но они просто будут крашить программу, и никак не будут обрабатываться.