эксепшины vs коды возврата
От: Vladik Россия  
Дата: 11.09.02 17:35
Оценка:
Привет!

Начинаю обещанный топик Сознательно начинаю его именно в форуме по С++, т.к. хочу ограничить обсуждение именно этим языком (применительно к другим языкам, например к джаве, мое отношение к сабжу отличается с точности почти до наоборот

Итак, если кратко: эксепшины имеют право на существование, но их применение следует ограничить исключительно исключительными ситуациями.
Примеры. Эксепшин на невозможность выделения памяти — это правильно. Ситуация однозначно исключительная (во всяком случае для 99% прог и для 99% кода оставшегося 1% прог) и свидетельствует о том, что все действительно очень плохо. Эксепшин на невозможность открытия файла, преобразовать строку в число и т.п. для библиотечных классов/функций — это неправильно. Потому как это заставляет программиста, использующего эти библиотечные функции явно ловить эксепшины даже тогда, когда код возврата ему абсолютно неинтересен.

Теперь подробнее, почему это так:
1) Синтаксис С++ в случае ловли эксепшинов заставляет городить:
value=default_value;
try
{
    value=f();
}
catch(exception)
{
}

вместо
value=default_value;
    f(&value);


В более практических случаях это здорово поганит читабельность. Кроме того, работает принцип: "на любом языке пишут так, как короче".

2) Компилятор С++ позволяет оставлять эксепшины без внимания:

void f()
{
    start_transaction();
    doit() ? commit_transaction() : rollback_transaction();
}


Программист, который пишет функцию doit() на очередной итерации разработки решил использовать в своей функции библиотечную функцию, кидающую эксепшин. Компилятор бессилен предупредить программиста, пишушего функцию f() о том, что некие действия могут быть вообще невыполнены, незавасимо от результата вызова doit().
Т.о. появляется фактор "неожиданности", который мне лично очень претит и который у меня ассоциируется с оператором goto

3) Отладка. Понять откуда и из-за чего пришел эксепшин в проге напичканной эксепшинами (без приема особых мер) бывает довольно затруднительно. А приходит он как раз из тех участков проги, в которых его никто не ожидает. В случае же непроверки кода возврата — прога просто вылетит на ближайшем assert'e.

4) Эффективность. С++ относится к тем языкам, используя которые, под эффективносью, в числе прочего, понимают и быстродействие и размер кода. Если на быстродействие эксепшины, как правило, и не сильно вляют, то код раздувают весьма эффективно.

5) Конструкторы/деструкторы. Распространяться не буду, уверен все и так поняли про что я. Опять упираемся в язык С++ как таковой. Т.е. все это заставить работать можно, но только зачем...

Все вышеперечисленные тезисы заставляют меня воздерживаться от применения механизма эксепшинов при разработке на С++. Поэтому просто приведу пару примеров тех редких случаев, когда я посчитал использование эксепшинов оправданным и использовал этот механизм.
1) Коммуникационный протокол связи по COM-порту. Эксепшины на ошибку COM-порта и "глобальный" таймаут приема/передачи. В обоих случаях дальнейшее продолжение связи бессмысленно и очень удобно кинуть эксепшин из "недр" и поймать его на самом "верху", нежели возиться с кучей кодов возврата.
2) Клиент, тупо вызывающий методы сервера. При любой ошибке вызова (не путать с результатом вызова) кидается эксепшин, который отлавливается и расшифровывается "наверху" в основном цикле приложения. При этом от клиента не требуется какой-либо особой реакци на эти ошибки (разве что показать юзеру). Т.е. юзер просто инициирует некое действие — клиент "переводит" его на сервер.
Как все запущенно...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.