При разработке моей первой «серьезной» библиотеки C ++ я спрашиваю себя:
Это хороший стиль, чтобы извлечь свои исключения, std::exception
и это потомки ?!
Даже после прочтения
Я все еще не уверен. Потому что, помимо обычной (но, возможно, не очень) практики, я бы предположил, как пользователь библиотеки, что библиотечная функция будет генерировать std::exception
s только в случае сбоя стандартных библиотечных функций в реализации библиотеки, и она ничего не может с этим поделать. Но тем не менее, при написании кода приложения, для меня это очень удобно, а также ИМХО хорошо выглядеть просто бросить std::runtime_error
. Также мои пользователи также могут рассчитывать на определенный минимальный интерфейс, например what()
или коды.
И, например, мой пользователь предоставляет неверные аргументы, что было бы удобнее, чем бросать std::invalid_argument
, не так ли? Таким образом, в сочетании с все еще распространенным использованием std :: exception, я вижу в коде других: почему бы не пойти еще дальше и извлечь из своего пользовательского класса исключений (например, lib_foo_exception), а также из std::exception
.
Мысли?
источник
std::exception
не означает , что вы броситьstd::exception
. Кроме того,std::runtime_error
наследуется лиstd::exception
в первую очередь отwhat()
методаstd::exception
, а не отstd::runtime_error
. И вам определенно следует создавать свои собственные классы исключений, а не генерировать общие исключения, такие какstd::runtime_error
.lib_foo_exception
класс наследует отstd::exception
пользователя, пользователь библиотеки будет ловитьlib_foo_exception
, просто ловяstd::exception
, в дополнение к тому, когда он ловит только библиотечный. Поэтому я мог бы также спросить, должен ли мой корневой класс исключения библиотеки наследоваться от std :: exception .lib_foo_exception
?» С наследованием отstd::exception
вас это можно сделатьcatch(std::exception)
ИЛИ путемcatch(lib_foo_exception)
. Не получая от этогоstd::exception
, вы бы поймали его тогда и только тогда , когдаcatch(lib_foo_exception)
.catch(...)
. Это происходит потому, что язык учитывает тот случай, который вы рассматриваете (и «недостойное поведение» библиотек), но это не лучшая современная практика.catch
сайты, а также более грубые транзакции, которые моделируют пользовательскую операцию. Если вы сравните его с языками, которые не продвигают идею обобщенного перехватаstd::exception&
, например, они часто имеют гораздо больше кода с промежуточнымиtry/catch
блоками, связанными с очень специфическими ошибками, что несколько уменьшает общность обработки исключений, поскольку она начинает появляться гораздо больший упор на ручную обработку ошибок, а также на все несопоставимые ошибки, которые могут произойти.Ответы:
Все исключения должны наследоваться от
std::exception
.Предположим, например, что мне нужно позвонить
ComplexOperationThatCouldFailABunchOfWays()
, и я хочу обработать любые исключения, которые он может выдать. Если все наследуетstd::exception
, это легко. Мне нужен только одинcatch
блок, и у меня есть стандартный интерфейс (what()
) для получения деталей.Если исключения НЕ наследуются
std::exception
, это становится намного хуже:Относительно того, выбрасывать
runtime_error
илиinvalid_argument
создавать собственныеstd::exception
подклассы, чтобы выбрасывать: мое эмпирическое правило - вводить новый подкласс всякий раз, когда мне нужно обрабатывать определенный тип ошибок иначе, чем другие ошибки (то есть всякий раз, когда мне нужен отдельныйcatch
блок).runtime_error
брошенный здесь означает что-то отличное от общей ошибки времени выполнения), то я рискую конфликтовать с другими видами использования существующего подкласса.invalid_argument
), то я повторно использую существующий класс. Я просто не вижу большой пользы от добавления нового класса в этом случае. (Основные принципы C ++ не согласны со мной здесь - они рекомендуют всегда использовать ваши собственные классы.)В Основных принципах C ++ продолжить обсуждение и примеры.
источник
catch (...)
(с буквальным многоточием)?catch (...)
полезен, только если вам не нужно ничего делать с тем, что выкинули. Если вы хотите что-то сделать - например, показать или записать конкретное сообщение об ошибке, как в моем примере - тогда вам нужно знать, что это такое.Это неверное предположение.
Стандартные типы исключений предоставляются для «обычного» использования. Они не предназначены для только использования стандартной библиотеки.
Да, сделать все в конечном итоге наследовать
std::exception
. Часто это включает в себя наследование отstd::runtime_error
илиstd::logic_error
. Все, что подходит для класса исключений, который вы реализуете.Это, конечно, субъективно - некоторые популярные библиотеки полностью игнорируют стандартные типы исключений, предположительно для отделения библиотек от стандартной библиотеки. Лично я считаю, что это очень эгоистично! Это делает отлов исключений, которые намного сложнее понять.
Говоря лично, я часто просто бросаю
std::runtime_error
и покончу с этим. Но это вступает в дискуссию о том, как гранулярно создавать классы исключений, а это не то, о чем вы просите.источник