From Novosibirsk, Russia? Our tiny company is looking for current or future rock-star developers.

October 12, 2006

When to throw exceptions?

На тему «какие ошибки достойны генерации исключений» написано и сказано столько бреда, что многим людям сложно разобраться и составить своё мнение. Вставлю и я свой комментарий на этот счёт.

Зачем создана обработка исключений?

1. Чтобы каждая функция не занималась обработкой ошибок. Дело в том, что бо́льшая часть кода успешно работает, когда всё идет хорошо, но не знает, что делать, если произошла ошибка. Исключения позволяют сконцентрировать обработку ошибок в одном месте минимальными усилиями программиста. Помимо прочего, это делает код функций более коротким и понятным, т. к. в них описан только успешный сценарий.

2. Исключения невозможно игнорировать, тогда как проверку кода ошибки можно забыть или просто отложить до лучших времен.

Некоторые люди считают, что исключения несут некую смысловую нагрузку и их нужно использовать только тогда, когда программа встречается с чем-то «исключительным» и «ненормальным». Это полный бред.

Во-певрых, то, что ненормально для одного клиента вашего кода, для другого абсолютно в порядке вещей.

Во-вторых, умные люди не видят в исключениях никакой магии. В Python исключения используются для выхода из циклов. В Ruby есть два вида исключений, один из которых специально упрощен для выхода из вложенных подпрограмм. Авторы JRuby (на Java) пытались использовать исключения для эмуляции параллельного исполнения в стиле Ruby.

В стандартной библиотеки C++ исключения кидаются, например, когда не получается открыть файл. Если задуматься, это нормальная ситуация — в 99% случаях вы получаете имя файла от пользователя, окружаете вызов open обработкой исключений и в catch сообщаете пользователю, что имя файла неверно. Если пользоваться логикой «исключения только для случаев, которые не ожидает программа», open должна была бы возвращать bool, а не кидать исключения.

Самое главное, что можно сказать про использование исключений — используйте их по-умолчанию, если только нет противопоказаний. Главное здесь — удобство клиентского кода; если вам кажется, что пользователю может быть удобно обработать какую-то ситуацию отдельно, кидайте исключение.

Случаев, когда исключения использовать не стоит, я вижу три:

1. Ошибка в процедуре, исполняющейся очень большое число раз. Скажем, функция Win32 API TryEnterCriticalSection создана ровно для того, чтобы очень часто вызываться в цикле, а механизм Critical Sections в принципе сделан для ускорения работы программы. Поэтому этой функции стоит возвращает bool (точнее, BOOL), а не кидать исключения. (Разумеется, это если бы функции Win32 API вообще могли бы кидать исключения в стиле C++.)

2. Особая ситуация, которая всегда обрабатывается там же и так же, как и нормальная ситуация. TryEnterCriticalSection могла бы быть подходящим примером, но еще более подходящий вариант — вызов fork() в Unix.

У fork есть три типа возврата: (1) не удалось создать процесс, (2) всё нормально и это родитель, (3) всё нормально и это ребёнок. В случае (2) функия возвращает PID (идентификатор процесса) созданного ребёнка. Можно было бы считать это основным результатом функции, а в случаях (1) и (3) кидать исключения. Однако случай (3) концептуально равноправен со случаем (2) и его обработкой точно занимается тот же самый код, который вызывает fork. Поэтому в третьем случае не стоит кидать исключения, тогда как в первом — стоит.

С другой стороны, например, вызов open для открытия файла сюда не попадает, поскольку обработкой ошибочного ввода пользователя может заниматься основная программа, тогда как open вызывать может какой-нибудь модуль разбора XML-файлов.

3. Если вызвавшая сторона может быть написана на другом языке или не может ловить исключения по другим причинам. Например, функция обработки сообщений в Win32 или обработчик сигналов в Unix не должен кидать исключения, потому что его вызывает операционная система.

3 comments:

Stepan Stolyarov said...

Таранцов, ты невъебенно пишешь, и у тебя охуительный блог, но он через жопу выдает RSS. Почему на каждый новый пост фидер ЖЖ забирает у тебя 15 старых?

Unknown said...

Имейте хороший агрегатор, господа!

Anonymous said...

Андрей пиши еще!
Для того чтобы получить известность за бугром - пиши на буржуском. Русские программеры и так поймут, еслт надо ))