Два анти-шаблона, которые невероятно распространены в большинстве базовых кодов, которые я разработал, - это логические значения возврата, указывающие на успех/неудачу, и общие интегральные коды возврата, чтобы указать более подробную информацию об ошибке.
Оба они очень похожи на C и не очень хорошо вписываются в С++ по моему скромному мнению.
Мой вопрос касается лучших практик, когда дело доходит до разработки исключений в вашей базе кода. Другими словами, какой лучший способ указать конечные возможности неудачи? Например, один из вышеупомянутых анти-шаблонов обычно имеет одну гигантскую перечисление с каждым значением перечисления, представляющим определенный вид сбоя, такой как FILE_DOES_NOT_EXIST
или NO_PERMISSIONS
. Обычно они поддерживаются как можно более общие, поэтому их можно использовать в нескольких несвязанных доменах (таких как сетевые компоненты и файлы IO-компонентов).
Дизайн, подобный этому, который можно было бы рассмотреть для исключений, заключается в подклассе одного конкретного типа исключения из std::exception
для каждого типа сбоя или вещи, которая может пойти не так. Поэтому в моем предыдущем примере у нас было бы следующее:
namespace exceptions {
class file_does_not_exist : public std::exception {};
class no_permissions : public std::exception {};
}
Я думаю, что это ближе к чему-то, что "чувствует себя лучше", но, в конце концов, это похоже на кошмар для обслуживания, особенно если у вас есть сотни этих "кодов ошибок" для перевода на классы.
Другой подход, который я видел, - просто использовать стандартные классы <stdexcept>
, такие как std::runtime_error
, и иметь строку со спецификой. Например:
throw std::runtime_error( "file does not exist" );
throw std::runtime_error( "no permissions" );
Эта конструкция гораздо более удобна в обслуживании, но делает ее сложной или неосуществимой, чтобы условно уловить любое из этих исключений, если они оба будут потенциально выбрасываться из одного и того же основного местоположения или вызова функции.
Итак, что было бы хорошим, поддерживаемым дизайном для типов исключений? Мои требования просты. Я хотел бы иметь контекстуальную информацию о том, что произошло (у меня закончилась нехватка памяти? Мне не хватает прав на файловую систему? Не удалось ли я выполнить предварительные условия вызова функции (например, плохие параметры)?), И мне также хотелось бы, чтобы иметь возможность действовать в соответствии с этой информацией. Возможно, я отношусь ко всем тем же, возможно, у меня есть определенные инструкции catch для определенных сбоев, поэтому я могу восстановить их по-другому.
Мои исследования по этому вопросу привели меня только к этому вопросу: дизайн класса исключений С++
Здесь пользователь задает аналогичный вопрос, который я есть, и его образец кода внизу очень симпатичен, но его базовый класс исключений не следует принципу открытого/закрытого, поэтому это не будет работать для меня.