Вы только что обнаружили, что исключения не являются серебряной пулей для обработки ошибок.
Исключения не защищают вас от изменений состояния ... все, что было выполнено без ошибок до возникновения исключения, должно быть отменено. Именно так работают исключения в Python, C ++, Java и многих других языках.
Иногда у вас может быть своего рода «внешняя» общая защита: например, если все, что вы делаете, это изменения в базе данных, поддерживающей транзакции, то вы можете использовать оператор перехвата верхнего уровня для выполнения «отката» вместо фиксации меняется, и вы получаете защиту, которую вы ищете. Если нет такой естественной «стены», защищающей от частичного изменения состояния, то с вещами гораздо сложнее правильно обращаться.
Сама причина того, что завершенные операции не будут отменены, состоит в том, что делает использование исключений нетривиальным, поскольку сложность проблем возрастает.
Обычно код можно классифицировать как исключение «безопасный» на нескольких уровнях:
В случае исключения все разрушается, и даже чистый выход или перезапуск невозможны. Это то, что обычно классифицируется как НЕ безопасное исключение.
В случае исключения код не завершит свою работу, и состояние подсистемы (экземпляр класса, библиотека) будет недопустимым. Однако вы можете безопасно перезапустить (например, вы можете уничтожить экземпляр или повторно инициализировать библиотеку). Это самое минимальное исключение безопасности.
В случае исключения код не завершит свою работу, и состояние подсистемы будет действительным, но не определенным. Вызывающий код может попытаться проверить текущее состояние и продолжать использовать подсистему, например, вместо ее повторной инициализации. Чуть лучше, чем 2.
В случае исключения код ничего не сделает, оставив состояние программы без изменений. Таким образом, либо запрос завершен без ошибок, либо сигнал об ошибке возвращается вызывающей стороне, и ничего не было изменено. Это, конечно, лучшее поведение.
Самая большая проблема с обработкой исключений состоит в том, что даже если у вас есть две очень безопасные части типа 4 A
и B
, простая последовательная композиция AB
не безопасна, поскольку в случае проблемы в B
Вы также должны отменить все, что A
завершил.
Также, если возможно получить исключение при выполнении 1/A
(т.е. при невыполнении того, что A
было в состоянии завершить), тогда у вас большие проблемы, потому что вы не можете ни сделать B
, ни восстановить состояние как это было раньше (это означает, что просто невозможно реализовать AB
как операцию типа 4).
Другими словами, хорошие кирпичи не сделают тривиального создания хороших конструкций (в отношении безопасности исключений).