Коды ошибок в си

Обработка ошибок Исключения в c++ c

Мы уже рассматривали базовые принципы защитного программирования и разобрались с тем, как можно организовать передачу и обработку ошибок на основе их числовых кодов. Если вы еще не ознакомились с указанной вводной частью, то рекомендую ее хотя бы пролистать, поскольку в этой заметке я буду периодически делать на нее отсылки.

Числовые коды — это хорошо, и в некоторых случаях у вас не будет других вариантов, кроме как пользоваться ими. Однако механизм исключений во многом оказывается более удобным и гибким. Давайте разберемся, почему это так.

Почему исключения?

Вновь вернемся к нашему примеру функции регистрации пользователя из первой части. Но на этот раз она не будет возвращать код ошибки. Вместо этого она возбудит исключение, если что-то пойдет не так:

Следующий вопрос, который у вас мог возникнуть: «А как организовать передачу информации о контексте, в котором произошла ошибка»? Когда мы использовали простые коды ошибок, у нас для этого было предусмотрено перечисление. Каждый элемент перечисления соответствовал тому или иному типу ошибки. Этот вариант широко распространен и неплохо работает, но он имеет свои ограничения. Например, с помощью одного лишь кода ошибки у нас нет возможности передать дополнительную информацию, чтобы уточнить причину ошибки. В случае же с исключениями у вас появляется выбор. Рассмотрим несколько наиболее очевидных вариантов.

Вариант 1. Коды ошибок. Опять

Мы ведь хотел уйти от кодов ошибок, а тут снова они? — В какой-то мере да. Однако на этот раз мы будем возвращать код не через явные выходные параметры функции, а с помощью экземпляра исключения:

Получилось не плохо, но эта реализация оказалась не намного проще, чем прежняя, в которой мы не использовали исключения. Более того, она не дает явных преимуществ, ведь нам все равно в конечном итоге придется работать с обычными кодами ошибок. на основе значений перечисления.

Заметим однако, что в более сложных случаях мы все же можем получить некую выгоду:

Вариант 2. Иерархия исключений

Если уж мы пишем ООП-код, то почему бы и ошибки не сделать объектами? Переход от кодов ошибок к иерархии классов осуществить не так уж сложно:

Теперь мы не только знаем, какая ошибка произошла, но и что послужило причиной. Причем, поскольку исключение все равно остается полноценным классом, мы можем расширять его так, как посчитаем нужным, добавляя столько дополнительных сведений об ошибке, сколько потребуется. Кроме того, не забывайте про полиморфизм. Если вы добавите всего один обработчик для базового класса исключения, то он сработает и для всех его подтипов:

Вариант 3. Текстовые сообщения

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

В качестве текстового сообщения вы можете передать какую-то полезную информацию, чтобы затем в обработчике ее вывести:

При этом в сообщениях, предназначенных для пользователей, не пытайтесь делать слишком подробные объяснения о технических деталях ошибки. Скорее всего, если пользователь увидит непонятный для него термин, то он просто не станет дочитывать сообщение. Хотя, конечно, ситуации бывают разные, поэтому в приложениях, рассчитанных на подготовленных специалистов, вполне допустимо использование технических подробностей об ошибках, вплоть до вывода внутренних сообщений, формируемых в исключениях. Приемлемым компромиссом в этом случае может стать реализация кнопки «Подробнее». То есть по умолчанию вы будете выводить лишь информацию о том, что что-то случилось, а все детали будут скрыты, но доступны для опытных пользователей по нажатию кнопки. Например, по этой схеме реализовано большинство сообщений об ошибках в Windows.

Коды ошибок, иерархия или текстовые сообщения?

Как обычно, все зависит от ваших целей. Интересным выходом может стать комбинированное использование всех трех вариантов. Например, мы можем реализовать класс исключения на случай некорректных значений полей с данными пользователя следующим образом:

Это лишь один из возможных подходов к созданию подобного класса исключения, и его можно улучшить. Но даже представленная реализация вполне неплохо справляется с комбинированием лучших качеств из рассмотренных нами вариантов использования исключений. В случае необходимости, чтобы возбудить исключение, мы передаем предопределенный код ошибки, которому соответствует шаблон текстового сообщения. Сами коды ошибок в этом случае мы определили внутри класса исключения, поскольку они непосредственно с ним связаны. Значения кодов ошибок в перечислении начинаются явным образом с 1000. Это поможет нам в дальнейшем не запутаться, если для других классов исключений мы будем определять коды в других диапазонах. Например, ошибки работы с БД мы можем определить, начав с 2000, а для сетевых соединений — с 3000.

Поскольку исключение InvalidFieldValueException сообщает о некорректном значении поля структуры, то в качестве дополнительной уточняющей информации мы передаем его значение. Название поля можно было передать тоже, но я решил, что текстового сообщения, сформированного на основании кода ошибки вполне достаточно. Обратите внимание, что для кода ошибки PASSWORD_IS_TOO_SHORT сам пароль, который был использован пользователем, в целях безопасности не выводится. С другой стороны, мы могли бы сделать некоторые уточнения в плане фактической длины полученного пароля, и допустимых диапазонах его значения.

Коротко об освобождении ресурсов

Источники:

https://tech-geek. ru/error-handling-exceptions-in-c/

Понравилась статья? Поделиться с друзьями:
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: