LINUX.ORG.RU

Расскажите о философии их использования

 ,


4

5

Уже много дней пишу на C++, но так сложилось, что в проектах, в которых я участвую, исключения не используются.

На днях задумался о том, чтобы протестировать их в одном из своих собственных проектов. Перед этим хотелось бы почитать какие-нибудь умные буквы о том, почему исключения - это хорошо.

Приветствуются ссылки на статьи на русском и английском языках.

Так же можете оставлять свое собственное мнение о практике и философии использования исключений в с++ коде.

★★★★★

В С++ философия такая: если фича есть, то это ещё не значит, что её стоит использовать.

PolarFox ★★★★★ ()

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

Потому что использование исключений уменьшает вероятность краша программы, если пользователь допустил ошибку при её использовании или просто криворукий

GreenTea ★★ ()
Ответ на: комментарий от PolarFox

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

trex6 ★★★★★ ()

чем больше ошибок выйдет сразу и при первых тактах наружу - тем лучше. Это индикатор, что идешь по правильному пути. Вообще let it crash как говорят в эрланге.

Смысл в том, что исключения нужно выкидывать как-можно чаще и быстрее, но по делу разумеется.

swwwfactory ★★ ()
Ответ на: комментарий от GreenTea

Потому что использование исключений уменьшает вероятность краша программы

Вероятность краша уменьшает только внимательное и вдумчивое программирование.

А вот это:

int main( int arc, char** argv)
{
    int result = 0;
    try
    {
        result = real_main( argc, argv);
    }
    catch(...)
    {
        result = -1;
    }
    return result;
}
дает лишь ложное ощущение Ынтерпрайзности и некрешовости.

trex6 ★★★★★ ()
Ответ на: комментарий от swwwfactory

чем больше ошибок выйдет сразу и при первых тактах наружу - тем лучше

В этом смысле, на мой взгляд, лучше всего работает ASSERT. Или я не прав?

trex6 ★★★★★ ()
Ответ на: комментарий от trex6

бгг ты просто не сталкивался с «клиенстским кодом» когда перед его вызовом нужно мыть руки, одевать ОЗК и готовить лопату.

а вообще исключения это костыль, для тех кто боится GOTO

Deleted ()
Ответ на: комментарий от trex6

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

А ассерты это вообще вещь!

swwwfactory ★★ ()
Ответ на: комментарий от trex6

Вероятность краша уменьшает только внимательное и вдумчивое программирование.

«Неуд». На пересдачу.

tailgunner ★★★★★ ()

Не использовать в библиотеках и десктопном софте, работающем с пользовательскими данными, использовать в движках игр.

/thread

quiet_readonly ★★★★ ()
Ответ на: комментарий от swwwfactory

Смысл в том, что исключения нужно выкидывать как-можно чаще и быстрее, но по делу разумеется.

Речь о C++, в нём отлов бага почти всегда сводится к воспроизведению бага и его отлову в отладчике. В такой ситуации assert лучше, т.к. не все среды по дефолту перехватывают выброс исключения в режиме отладки.

quiet_readonly ★★★★ ()
Ответ на: комментарий от quiet_readonly

использовать в движках игр

Аргументация поможет разобраться, почему для игр это будет полезно. Часть моих собственных проектов - это как раз игры.

trex6 ★★★★★ ()
Ответ на: комментарий от trex6

Вероятность краша уменьшает только внимательное и вдумчивое программирование.

«Неуд». На пересдачу.

Аргументируйте.

Если 50 лет software engineering прошли мимо тебя, и ты до сих пор полагаешься на «внимание и вдумчивость», вот тебе несколько ключевых слов для гугла: strong typing, type safety, design by contract, и даже separation of concerns.

tailgunner ★★★★★ ()
Ответ на: комментарий от tailgunner

strong typing, type safety, design by contract, и даже separation of concerns

Ок. Но что-то подобное я и имел в виду под «вдумчивым» программированием.

Может быть и книжку хорошую посоветуете, чтобы наверстать упущенные 50 лет? Можно (нужно?) на английском.

trex6 ★★★★★ ()
Ответ на: комментарий от trex6

Аргументация поможет разобраться, почему для игр это будет полезно. Часть моих собственных проектов - это как раз игры.

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

  • Для графических ресурсов важна целостность, и при малейшем отклонении ресурса от требований движка запросто можно кинуть исключение с описанием проблемы из любого места, а уровнем выше скинуть текст исключения в лог, заменить ресурс заглушкой: жёлто-чёрной в полоску текстурой или моделью в виде жёлтого восклицательного знака. Так проще всего ловить проблемы в ресурсах, да и игрок не сильно обидится.
  • Сохранения обычно дублируются и повреждение одного из них не так плохо, как падение игры.
  • Контент формируется долго, а поставляется в почти неизменном виде (не считая пользовательских сейвов, которые в том же morrowind являются просто патчем на контент). Чем меньше движок будет вылетать и чем яснее будет визуализировать проблемы в контенте, тем лучше.
quiet_readonly ★★★★ ()
Ответ на: комментарий от trex6

strong typing, type safety, design by contract, и даже separation of concerns

Ок. Но что-то подобное я и имел в виду под «вдумчивым» программированием.

Всё указанное - это инструменты, которые помогают экономить «вдумчивость и внимание».

Может быть и книжку хорошую посоветуете, чтобы наверстать упущенные 50 лет?

Хотел бы я, чтобы результат всех 50 лет описывался в одной книге, но, если она и существует, я о ней не знаю. Думаю, тебе следует начать с учебников, которые рекомендуют продвинутые ВУзы типа MIT. Или, если нужна единая точка входа, то почитай «Design and evolution of C++» - Страуструп очень грамотный мужик и при конструировании Си++ изучил очень много всего, от Ады до SML. Нужно только читать внимательно.

tailgunner ★★★★★ ()
Ответ на: комментарий от quiet_readonly

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

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

tailgunner ★★★★★ ()
Ответ на: комментарий от quiet_readonly

да, это так. Уместно уточнение насчет ц++ - согласен, спасибо. Цпп не является моим основным языком, но тема очень актуальна и занятна.

В этой среде отлов исключений неблагодарное занятие - ассерты удобнее в отладке.

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

Но ценность программы определяется в итоге ценностью для ее потребителя, если в продакшене отключены ассерты, а исключениям не уделялось должно внимание, то получим типа окошко с заголовком error и надписью success слева от «кирпича» ))

В этом случае только программист или специалист сможет понять, что надо запустить прогу с ассертами. Потом нужно будет в службу поддержки отправить лог с ассертами. Но это характерно для гуев. Для консольных прог все проще.

Кстати амарок подобным образом работает вроде как - ассертами и цветными логами.

swwwfactory ★★ ()
Ответ на: комментарий от tailgunner

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

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

Исключения хороши тем, что собирают какую-то информацию об ошибке. Но если процесс сбора информации нельзя кастомизировать - нафиг он не нужен в библиотеке, проще по кодам возврата и errorString самостоятельно сформировать отчёт о проблеме.

Раз кастомизировать нельзя, то от исключений одни беды: в документации к библиотеке информация об исключениях обычно скудная, да и компилятор проверить тут ничего не может. Коды возврата, API для получения лога ошибки и warn_unused_result гораздо приятнее.

В десктопном софте очень часто программа должна полностью завершить операцию и без этого бесполезна. В таком случае толку 0 от исключений, код возврата ничем не хуже.

quiet_readonly ★★★★ ()
Ответ на: комментарий от quiet_readonly

Но если процесс сбора информации нельзя кастомизировать - нафиг он не нужен в библиотеке, проще по кодам возврата и errorString самостоятельно сформировать отчёт о проблеме.

А если сообщение и код ошибки несет исключение - это плохо и неправильно?

В десктопном софте очень часто программа должна полностью завершить операцию и без этого бесполезна. В таком случае толку 0 от исключений, код возврата ничем не хуже.

Мде. Ты понимаешь, что код возврата может просто потеряться в недрах, или веришь во вдумчивость и внимание?

tailgunner ★★★★★ ()
Ответ на: комментарий от tailgunner

А если сообщение и код ошибки несет исключение - это плохо и неправильно?

Это лишено преимуществ. А недостатки я указал.

Мде. Ты понимаешь, что код возврата может просто потеряться в недрах, или веришь во вдумчивость и внимание?

warn_unused_result или

void generatesReturnCode(int &returnCode);

quiet_readonly ★★★★ ()
Ответ на: комментарий от quiet_readonly

недостатки я указал.

Это не недостатки исключений.

warn_unused_result

ЕМНИП, «err = fun()», и ворнинга не будет. Но анализа err это не гарантирует.

Есть два здравых аргумента против использования исключений - сложность/несовместимость рантаймов и то, что описывается словами Шустрика

My argument was that with systems programming you should avoid «unknown» as much as possible. By handling error as soon as they happen you basically say while it is error it is not «unknown» or «unexpected» state. It's just a different, perfectly valid and well-understood codepath.

tailgunner ★★★★★ ()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от i-rinat

Отличные статьи. Всем рекомендую к прочтению обе части. Единственное, я не очень понял, почему автор во второй отказывается от использования итераторов.

trex6 ★★★★★ ()
Ответ на: комментарий от tailgunner

Это не недостатки исключений.

Отсутствие упоминаний в документации и проверок компилятора - это не недостатки? Мы вообще-то о практике и C++ говорим, а не о том, как хорошо было бы иметь исключения в супер-языке будущего.

ЕМНИП, «err = fun()», и ворнинга не будет. Но анализа err это не гарантирует.

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

try {
    doException();
} catch (...) {
}

quiet_readonly ★★★★ ()

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

dmfd ()

единсвенный случай, когда надо их использовать - фейл в конструкторе класса.

nanoolinux ★★★★ ()
Ответ на: комментарий от quiet_readonly

внимание ревьювера.

То есть ты адепт «вдумчивости и внимания». Okay.

tailgunner ★★★★★ ()
Ответ на: комментарий от tailgunner

То есть ты адепт «вдумчивости и внимания». Okay.

4.2

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

quiet_readonly ★★★★ ()

Роберт Мартин «Чистый код». У него там есть целая глава (или раздел) про использование исключений. Не в разрезе С++, конечно(скорее в разрезе Java), но пара дельных советов там есть.

Из личного опыта. В одном проекте очень удачно заюзали исключения для уменьшения дублирования кода и централизованной обработки ошибок.

kulti ★★ ()
Ответ на: комментарий от quiet_readonly

Вы выдумали нелепую придирку, что warn_unused_result, видите ли, можно заглушить.

Не заглушить, а случайно сделать ошибку. Да, такой вот я придира - придираюсь к человеческим ошибкам.

tailgunner ★★★★★ ()
Ответ на: комментарий от trex6

Единственное, я не очень понял, почему автор во второй отказывается от использования итераторов.

  1. Итератор может бросить исключение;
  2. В приведённом им примере не добиться O(1) без обрушения абстракции (надумано, как мне кажется);
  3. Многословность.
i-rinat ★★★★★ ()
Ответ на: комментарий от i-rinat

Итератор может бросить исключение

А разве нет возможность скомпилировать проект без использования исключений? Какой-нибудь --nothrow?

2 - я тоже не очень понял эту его мысль

3 - c++11::auto частично решает проблему. Или typedef в хидере класса.

trex6 ★★★★★ ()
Последнее исправление: trex6 (всего исправлений: 1)
Ответ на: комментарий от trex6

А разве нет возможность скомпилировать проект без использования исключений?

Не использовать STL.

c++11::auto частично решает проблему. Или typedef в хидере класса.

Это способы спрятать проблему. Лично мне кажется, что лучше писать явно. Вероятность сделать одну и ту же ошибку сразу в двух местах меньше. А с auto проглатывает всё что угодно. Но для коротких набросков удобно, я оценил :)

i-rinat ★★★★★ ()
Ответ на: комментарий от GreenTea

если пользователь допустил ошибку при её использовании

Это как?

J ★★★★ ()

Кидай их из деструкторов побольше. Не используй умные указатели. Кидай эксепшены в виде указателей на объект. Кидай эксепшны из конструкторов глобальных статических объектов и успешно отлавливай их. И много еще всяких успешных стратегий.

nerdogeek ()

Когда-то давно использовал исключения. Последние несколько лет - нет. Это в основном вызвано использованием Qt, где преобладают коды возврата. Кроме того, компиляция без исключений (-fno-exceptions) сильно уменьшает бинарник и вроде бы как повышает производительность.
Теперь же думаю надо к ним всё же вернуться. А как иначе ещё можно отловить валидность указателей? Проверка на NULL(nullptr) не всегда может дать корректный результат. Единственное решение - проверка практикой (упадёт код/не упадёт) под контролем исключений.
Кроме того, постоянная проверка всех кодов ошибок настолько расширяет код, что, кажется, уже теряется полезный эффект от -fno-exceptions.
Но не нужно позволять им выходить за пределы функции. Вообще вот эта статья
http://www.250bpm.com/blog:4
хорошая, но мне кажется более грамотным решением здесь будет комбинация обоих подходов. Любая моя функция везде и всегда имеет право только возвращать коды ошибок. Внутри этих функций делаем один большой try-catch(...), ловим все ошибки и формируем код возврата. Никаких исключений по стеку не передаём. Но если они всё же возникли в библиотечном коде, их конечно нужно поймать в main(). Порождать свои классы исключений в таком случае особого смысла не имеет.
Такая c++-программа будет очень похожа на c-программу, но будет более надёжна из-за обращения с указателями.

gogi ()
Ответ на: комментарий от nerdogeek

Зачем, если можно в main разименовать nullptr?

trex6 ★★★★★ ()
Ответ на: комментарий от trex6
catch(...)
    {
        result = -1;
    }
    return result;

а никто и не говорил, что не нужно выводить подобные сведения об исключении. в питончике для этого есть logging.exception(), на пример.

AGUtilities ★★★ ()

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

yoghurt ★★★★★ ()

При использовании исключений главный вопрос: «что считать исключительной ситуацией?». И однозначный ответ думаю никто не даст.

m0rph ★★★★★ ()

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

Разумеется, всё это при грамотном использовании исключений в этом модуле.

jeuta ★★★★ ()

Исключения - синтаксический сахар от ООП-фагов и тонкий тролинг смуглолицых собратьев по клавиатуре.
Лучше чтоб коредамп кидал, тогда проще находить место проблемы, тем более что есть любители кидать эксепшн одного и того же типа из 100500 разных мест.
Программа или работает, или нет. Как coreutils. Хотя они всегда работают.

nerdogeek ()
Ответ на: комментарий от nerdogeek

А какое отношения исключения С++ имеют к коредампам?

anonymous ()

исключения - это хорошо

исключения в С++ это не очень хорошо

x0r ★★★★★ ()
Последнее исправление: x0r (всего исправлений: 1)
Ответ на: комментарий от x0r

Ну да, false вернуть хорошо, а исключение плохо. :)

anonymous ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.