Подтвердить что ты не робот

Стандартное или настраиваемое исключение в С++?

Для кода библиотеки лучше ли создавать и вызывать собственный класс исключений (library:: Exception) или просто бросать стандартные исключения (runtime_error, invalid_argument и т.д.)?

4b9b3361

Ответ 1

Обычно лучше специализировать (наследовать) стандартное исключение и бросать его.

Таким образом, можно будет поймать его как общее исключение, просто поймав std::exception, но вы также можете поймать конкретный тип настраиваемого исключения, если вам нужен более специализированный код.

Также смотрите С++ Faq о том, что делать.

Ответ 2

Как правило, вы должны бросать экземпляры классов в заголовок stdexcept или его подклассы. Какой класс в точности имеет смысл, зависит от конкретной проблемы. Я думаю, что бросание экземпляров "классов категорий" std::logic_error и std::runtime_error редко полезно, поскольку они не имеют неотъемлемого значения; они используются, чтобы различать две основные ситуации, в которых могут возникать исключения:

  • Подклассы std::logic_error должны быть выбраны функцией, если она вызывается, но не все предварительные условия выполняются. Исключением является ошибка вызывающего абонента, поскольку он не смог обеспечить необходимые предварительные условия. Для этой категории вам обычно нужно выбирать между метанием и undefined; это компромисс между надежностью и эффективностью (например, std::vector::at() vs. std::vector::operator[]. Эти исключения часто не могут быть обработаны, они являются результатом ошибок в программе.

  • Подклассы std::runtime_error должны быть выбраны функцией, если выполнены все предварительные условия, но функция не может удовлетворять постусловиям или разрывам инварианты по причинам, не зависящим от программы (например, файл не существует, сетевое соединение потеряно или недостаточно памяти). Обычно эти исключения обрабатываются.

Я думаю, что доступные классы логических ошибок (например, invalid_argument) часто достаточно хороши, потому что, если они возникают, код обычно должен быть исправлен, и нет причин для сложных процедур обработки. С другой стороны, классы ошибок во время выполнения в стандартной библиотеке по своей природе гораздо менее гибкие и охватывают в основном те области, где сама стандартная библиотека должна исключать исключения. Для вашего приложения вы почти всегда должны унаследовать от этих классов ошибок во время выполнения. Например, класс, управляющий ресурсом X операционной системы, должен выбросить X_creation_error, который наследует от std::runtime_error, если конструктор не может выделить ресурс.

Несколько виртуальных наследований часто полезно для классов исключений. Вы можете наследовать от std::runtime_error или других stdexcept классов, от некоторого "класса маркеров", определенного для вашей библиотеки, и от boost::exception до получить дополнительные преимущества Boost.Exception library. Рекомендуется использовать Boost.Exception, особенно Типы исключений как простые семантические теги и Использование виртуального наследования в типах исключений.

Ответ 3

Исходное исключение IMHO. Клиенты вашей библиотеки оценят это. Он будет знать, что именно вызывает исключение.

Ответ 4

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

В большинстве моих кодов (в основном, число - если вы делаете, например, IO, ситуация другая), я бросаю стандартные исключения (runtime_error, invalid_argument,...), потому что они, как правило, указывают на то, что не может быть легко восстановлено (кроме, возможно, invalid_argument) и которое, скорее всего, не будет зависеть от кода пользователя (за исключением, возможно, на верхнем уровне, чтобы передать пользователю окно сообщения).

Если есть какое-то исключение, которое предполагается поймать типичным кодом пользователя, например. bad_custom_cast или bad_market_data_identifier вместо того, чтобы пузыряться до основного (например, сбой в числовой подпрограмме или bad_alloc), я создаю собственный класс. Но это довольно редко.