Ответ 1
Стандартная библиотека С++. Иерархия исключений ИМХО довольно произвольна и бессмысленна. Например, это, вероятно, просто создаст проблемы, если кто-нибудь начнет фактически использовать, например. std::logic_error
вместо прекращения, когда это ясно, что программа имеет очень неприятную ошибку и торговлю;. Поскольку стандарт ставит его,
"Отличительной особенностью логических ошибок является то, что они связаны с ошибками во внутренней логике программы".
Таким образом, в тот момент, когда в противном случае было бы разумно выбросить std::logic_error
, состояние программы может быть непредсказуемо затушевано, и продолжение выполнения может привести к тому, что данные пользователя будут повреждены.
Тем не менее, как и std::string
, стандартная иерархия классов исключений имеет действительно очень важную и полезную функцию, а именно, что она формально стандартная.
Таким образом, любой настраиваемый класс исключений должен быть получен косвенно или (хотя я бы не рекомендовал его) непосредственно из std::exception
.
Как правило, когда дебаты о настраиваемых классах исключений бушевали десять лет назад, я рекомендовал получить только от std::runtime_error
, и я по-прежнему рекомендую это. Это стандартный класс исключений, который поддерживает пользовательские сообщения (другие обычно имеют жестко запрограммированные сообщения, которые предпочтительно не следует изменять, поскольку они имеют ценность в распознавании). И можно утверждать, что std::runtime_error
является стандартным классом исключений, который представляет собой восстановимые отказы (в отличие от неустранимых логических ошибок, которые могут быть исправлены во время выполнения) или, как полагает стандарт,
"ошибки времени выполнения связаны с событиями, выходящими за рамки программы. Их невозможно легко предсказать заранее.
Иногда механизм исключений С++ используется для других вещей, рассматриваемых как просто динамический механизм перехода на динамический уровень. Например, умный код может использовать исключения для распространения успешного результата из цепочки рекурсивных вызовов. Но исключение-как-неудача является наиболее распространенным использованием, и что, как правило, оптимизируются исключения С++, поэтому в основном имеет смысл использовать std::runtime_error
как root для любой пользовательской иерархии классов исключений – даже если это заставляет кого-то, кто хочет быть умным, бросать "неудачу" - указание исключения, указывающего на успех & hellip;
Стоит отметить: существует три стандартных подкласса std::runtime_error
, а именно std::range_error
, std::overflow_error
и std::underflow_error
, и что, вопреки тому, что указывают их имена, последние два не должны генерироваться с плавающей запятой операций и на практике не генерируются операциями с плавающей запятой, но AFAIK генерируется только некоторыми; сюрприз! – std::bitset
. Проще говоря, стандартная библиотека иерархии классов, как мне кажется, была заброшена там просто для удобства, без каких-либо реальных веских причин или существующей практики, и даже без проверки подлинности. Но, возможно, я пропустил это, и если да, то у меня все еще есть что-то новое, чтобы узнать об этом.: -)
Итак, std::runtime_error
это то.
В верхней части иерархии пользовательских классов исключений, с С++ 03, было полезно добавить важный материал, отсутствующий в стандартных исключениях С++ 03:
-
Виртуальный
clone
метод (особенно важный для передачи исключений через C-код). -
Виртуальный
throwSelf
метод (та же основная причина, что и для клонирования). -
Поддержка цепочки исключений (стандартизация формата).
-
Поддержка переноса кода сбоя (например, код ошибки Windows или Posix).
-
Поддержка получения стандартного сообщения из приведенного кода причины сбоя.
С++ 11 добавила поддержку для большей части этого, но за исключением проверки новой поддержки кодов причин сбоев и сообщений, и отмечая, что, к сожалению, она довольно специфична для Unix и не очень подходит для Windows, я haven & rsquo; t все же использовал его. Во всяком случае, для полноты: вместо добавления клонирования и виртуального ретронирования (что лучше всего, что обычный программист приложений может выполнять в пользовательской иерархии классов исключений, потому что в качестве программиста приложений вы не можете поднять текущий объект исключения из хранилища, что реализация & rsquo; используется использование исключения s), в стандарте С++ 11 добавляются бесплатные функции std::current_exception()
и std::rethrow_exception()
, а вместо поддержки цепочки исключений исключений добавляется класс mixin std::nested_exception
и бесплатные функции std::rethrow_nested
и std::rethrow_if_nested
.
Учитывая частичную поддержку С++ 11 для указанных выше маркеров, новая и современная иерархия классов исключений должна лучше интегрироваться с поддержкой С++ 11 вместо адресации недостатков С++ 03. Ну, за исключением кода С++ 11, который кажется очень непригодным для программирования Windows. Таким образом, в верхней части пользовательской иерархии, прямо под std::runtime_error
, в идеале должен быть хотя бы один общий класс исключений и получен из этого один класс исключений, который поддерживает распространение кодов сбоев.
Теперь, наконец, к сути вопроса: следует ли лучше всего получить уникальный класс исключений для любой возможной причины сбоя или, по крайней мере, для серьезных сбоев?
Я говорю "нет": DON & T; T ADD NEEDLESS COMPLEXITY.
Если или где это может быть полезно для вызывающего, чтобы отличить определенную причину сбоя, для этого очень полезен отдельный класс исключений. Но в большинстве случаев единственная информация, представляющая интерес для вызывающего, является единственным фактом, что произошло исключение. Очень редко, что различные причины отказа приводят к различным попыткам исправления.
Но как насчет причин сбоев?
Ну, когда это то, что дает вам базовый API, просто добавлена работа по созданию соответствующих классов исключений. Но, с другой стороны, когда вы сообщаете о сбое в цепочке вызовов, и вызывающему абоненту может понадобиться знать точную причину, тогда использование кода для этого означает, что вызывающему абоненту придется использовать некоторую вложенную проверку и отправку внутри catch
. Таким образом, это разные ситуации: (A) ваш код является исходным источником индикации отказа, в отличие от (B) вашего кода, например. функция Windows или Posix API, которая терпит неудачу, и что это указывает на причину сбоя с помощью кода причины сбоя.