Хотя я согласен с тем, что отлов ...
без повторной обработки действительно неверен, я, тем не менее, считаю, что использование таких конструкций:
try
{
// Stuff
}
catch (...)
{
// Some cleanup
throw;
}
Приемлемо в тех случаях, когда RAII не применяется . (Пожалуйста, не спрашивайте ... не всем в моей компании нравится объектно-ориентированное программирование, а RAII часто рассматривается как "бесполезная школа" ...)
Мои коллеги говорят, что вы всегда должны знать, какие исключения следует выдавать, и что вы всегда можете использовать такие конструкции, как:
try
{
// Stuff
}
catch (exception_type1&)
{
// Some cleanup
throw;
}
catch (exception_type2&)
{
// Some cleanup
throw;
}
catch (exception_type3&)
{
// Some cleanup
throw;
}
Есть ли хорошая практика в этих ситуациях?
...
» , а мой вопрос сосредоточиться на «Должен ли я лучше поймать...
или<specific exception>
перед тем Повторное выбрасывание»main
,catch(...) { return EXIT_FAILURE; }
может также быть прямо в коде , который не работает под отладчиком. Если вы не поймаете, то стек не может быть размотан. Только когда ваш отладчик обнаруживает неперехваченные исключения, вы хотите, чтобы они ушлиmain
.Ответы:
Ваш коллега, я бы не хотел этого говорить, очевидно, никогда не работал с библиотеками общего назначения.
Как в мире могут такие классы, как
std::vector
даже притворяться, знать, что выбросят конструкторы копий, при этом гарантируя безопасность исключений?Если бы вы всегда знали, что будет делать вызываемый объект во время компиляции, тогда полиморфизм будет бесполезен! Иногда вся цель состоит в том, чтобы абстрагироваться от того, что происходит на более низком уровне, поэтому вы специально не хотите знать, что происходит!
источник
...
?То, что вы, кажется, пойманы, является определенным адом того, кто пытается получить их пирог и съесть это также.
RAII и исключения предназначены идти рука об руку. RAII - это средство, с помощью которого вам не нужно писать много
catch(...)
утверждений для очистки. Это произойдет автоматически, как само собой разумеющееся. И исключения - единственный способ работать с объектами RAII, потому что конструкторы могут только успешно или бросить (или поместить объект в состояние ошибки, но кто этого хочет?).catch
Заявление может сделать один из двух вещей: обрабатывать ошибки или исключительные обстоятельства, или делать работу по очистке. Иногда это делает и то и другое, но каждоеcatch
утверждение существует для выполнения хотя бы одного из них.catch(...)
неспособен сделать правильную обработку исключений. Вы не знаете, что является исключением; Вы не можете получить информацию об исключении. У вас нет абсолютно никакой информации, кроме того факта, что исключение было сгенерировано чем-то внутри определенного блока кода. Единственная законная вещь, которую вы можете сделать в таком блоке - это очистка. А это значит, что выкидывать исключение в конце очистки.Что RAII дает вам в отношении обработки исключений, так это бесплатная очистка. Если все в RAII инкапсулировано правильно, то все будет правильно очищено. Вам больше не нужно, чтобы
catch
заявления делали очистку. В этом случае нет причин писатьcatch(...)
заявление.Так что я бы согласился, что
catch(...)
это в основном зло ... временно .Это положение является надлежащим использованием RAII. Потому что без этого вы должны быть в состоянии сделать определенную очистку. Там нет обойти это; Вы должны быть в состоянии сделать уборку. Вы должны быть в состоянии гарантировать, что бросок исключения оставит код в разумном состоянии. И
catch(...)
это жизненно важный инструмент для этого.Вы не можете иметь одно без другого. Нельзя сказать, что оба RAII и
catch(...)
плохие. Вам нужен по крайней мере один из них; в противном случае вы не исключение.Конечно, есть одно действительное, хотя и редкое использование,
catch(...)
которое даже RAII не может изгнать: получениеexception_ptr
перенаправления кому-то еще. Обычно черезpromise/future
аналогичный интерфейс.Ваш коллега - идиот (или просто ужасно невежественный). Это должно быть сразу видно из-за того, сколько кода он предлагает вам скопировать и вставить. Очистка для каждого из этих операторов catch будет точно такой же . Это кошмар обслуживания, не говоря уже о читабельности.
Вкратце: это проблема, которую RAII был создан для решения (не то, что он не решает другие проблемы).
Что меня смущает в этом представлении, так это то, что большинство людей считают, что RAII - это плохо. Как правило, аргумент звучит так: «RAII - это плохо, потому что вы должны использовать исключения, чтобы сигнализировать о сбое конструктора. Но вы не можете генерировать исключения, потому что это небезопасно, и вам придется иметь много
catch
операторов, чтобы все очистить». Что является ошибочным аргументом, потому что RAII решает проблему, которую создает отсутствие RAII.Скорее всего, он против RAII, потому что он скрывает детали. Вызовы деструкторов не сразу видны на автоматических переменных. Таким образом, вы получаете код, который вызывается неявно. Некоторые программисты действительно ненавидят это. По-видимому, до такой степени, что они думают, что имеют 3
catch
оператора, и все они делают то же самое с кодом копирования и вставки - это лучшая идея.источник
Два комментария, правда. Во-первых, в идеальном мире вы всегда должны знать, какие исключения могут быть созданы, на практике, если вы имеете дело со сторонними библиотеками или компилируете с помощью компилятора Microsoft, это не так. Более конкретно, однако; даже если вы точно знаете все возможные исключения, уместно ли это здесь?
catch (...)
выражает намерение гораздо лучше, чемcatch ( std::exception const& )
, даже если предположить, что все возможные исключения происходят изstd::exception
(что было бы в идеальном мире). Что касается использования нескольких блоков улова, если нет единой базы для всех исключений: это просто запутывание и кошмар обслуживания. Как вы узнаете, что все виды поведения идентичны? И что это было намерение? А что произойдет, если вам придется изменить поведение (например, исправление ошибок)? Это слишком легко пропустить один.источник
std::exception
и пытается каждый день обеспечивать его использование в нашей кодовой базе. Я предполагаю, что он пытается наказать меня за использование кода и внешних библиотек, которые он сам не написал.std::vector<>
может вызвать любое исключение по любой причине.Я думаю, что ваш коллега перепутал несколько хороших советов - вы должны обрабатывать известные исключения в
catch
блоке только тогда, когда вы их не выбрасываете повторно.Это означает:
Это плохо, потому что он будет скрывать любую ошибку.
Тем не мение:
Хорошо - мы знаем, с чем имеем дело, и нам не нужно показывать это вызывающему коду.
Точно так же:
Хорошо, даже лучше всего, код для решения общих ошибок должен быть кодом, который их вызывает. Лучше, чем полагаться на вызываемого, знать, что транзакция требует отката или чего-то еще.
источник
Любой ответ « да» или « нет» должен сопровождаться обоснованием того, почему это так.
Сказать, что это неправильно, просто потому, что меня так учили, - это просто слепой фанатизм.
Писать то же самое
//Some cleanup; throw
несколько раз, как в вашем примере, неправильно, потому что это дублирование кода, а это бремя обслуживания. Написание всего один раз лучше.Писать a,
catch(...)
чтобы заставить замолчать все исключения, неправильно, потому что вы должны обрабатывать только те исключения, которые вы знаете, как обрабатывать, и с этим подстановочным знаком вы можете хранить больше, чем ожидаете, и это может заставить замолчать важные ошибки.Но если вы перебрасываете после a
catch(...)
, то последнее обоснование больше не применяется, так как вы на самом деле не обрабатываете исключение, поэтому нет никаких причин, по которым это не рекомендуется.На самом деле я сделал это для входа в чувствительные функции без каких-либо проблем:
источник
Log(...)
не можем бросить.Я в целом согласен с настроением постов здесь, мне действительно не нравится шаблон отлова определенных исключений - я думаю, что синтаксис этого все еще находится в зачаточном состоянии и еще не в состоянии справиться с избыточным кодом.
Но так как все говорят это, я расскажу о том факте, что, хотя я использую их экономно, я часто смотрел на одно из своих утверждений «catch (Exception e)» и говорил: «Черт, я хотел бы позвонить Выясните конкретные исключения того времени ", потому что, когда вы приходите позже, часто приятно знать, каково было намерение и что клиент может бросить с первого взгляда.
Я не оправдываю позицию «Всегда используйте x», просто говорю, что иногда приятно видеть их в списке, и я уверен, что именно поэтому некоторые люди считают, что это «правильный» путь.
источник