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

Как сделать разумное решение о том, какое стандартное исключение бросить?

Мы знаем, что класс исключения имеет два производных класса: logic_error и runtime_error.

logic_error имеет четыре производных класса: domain_error, invalid_argument, length_error и out_of_range. > .

runtime_error имеет три производных класса: range_error, overflow_error и underflow_error.

Хотя некоторые из них не требуют пояснений, например overflow_error и underflow_error, некоторые из них не так понятны, особенно range_error, как MSDN, так и cplusplus просто говорит "сообщить об ошибке диапазона", что близко к молчанию, как это отличается от out_of_range и domain_error???

Другой вопрос, когда я бросаю исключение, которое я должен выбрать? Например, In reverse_string (char * s), какое исключение выбрано, когда s равно NULL? В float calc_ellipse_area (float a, float b), который нужно бросить, когда a или b равно <= 0? Что бросать, когда a == b (строго говоря, круг не является эллипсом!)?

Наконец, на самом деле, действительно ли имеет значение, если я создаю исключение, которое неправильно классифицировано?

4b9b3361

Ответ 1

Например, In reverse_string (char * s), какое исключение выбрано, когда s равно NULL?

В float calc_ellipse_area (float a, float b), который нужно бросить, когда a или b равно <= 0? Что бросать, когда a == b (строго говоря, круг не является эллипсом!)?

Для обоих из них используйте std::invalid_argument.

Или вы можете определить собственное исключение с именем null_argument, происходящее из std::logic_error (или из std::invalid_argument), и использовать его для аргумента NULL.

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

Например, если вы хотите исключить исключение, когда вы сталкиваетесь с недопустимым индексом, то вы можете использовать std::out_of_range или определить более определенный класс с именем index_out_of_range, полученный из std::out_of_range.

Действительно ли это важно, если я создаю исключение, которое неправильно классифицировано?

Да, это имеет значение. Например, это повышает читаемость вашего кода. Если вы бросаете std::logic_error, когда встречается недопустимый индекс, значит, он мало чем отличается от читаемости, но вместо этого, если вы бросаете std::out_of_range, это значительно увеличивает читаемость. И если вы выбросите index_out_of_range, он будет увеличиваться еще больше, поскольку он более конкретный.

Ответ 2

Логическая ошибка - это (теоретически) результат ошибки программиста. Ошибка выполнения - это то, что программисту не удалось избежать.

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

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

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

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

Если что-то начинается с 01 февраля 2011 года, дата окончания "01 января 2011 года" является недопустимым аргументом, а "31 февраля 2011 года" выходит за пределы допустимого диапазона. Датой окончания "рыбы и чипсов" является ошибка домена. Ошибки длины часто связаны с размером буфера, но это может также включать слишком много или слишком мало входных данных или что-то в этом роде.

Ошибка диапазона аналогична ошибке вне диапазона, за исключением контекста (время выполнения, а не логическое). например Количество доступных принтеров = 0. Переполнение и недополнение более или менее понятны.

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

Это действительно важно, если вы будете обрабатывать разные исключения по-разному. Если вы просто собираетесь отображать (или регистрировать) сообщение и выполнять его, не имеет значения, какое исключение вы используете.

Ответ 3

Разница между out_of_range и range_error находится в описании их родительских классов:

logic_error: Этот класс определяет тип объектов, которые были выбраны как исключения для отчета ошибки во внутренней логике программы. Это теоретически предотвратимой.

runtime_error: этот класс определяет тип объектов, которые были выбраны как исключения для отчета ошибки, которые могут быть определены только во время выполнения.

Ошибка домена для специфических математических функций. Таким образом, ваш calc_ellipse_area мог бы разумно выбросить ошибку домена на отрицательное значение (и вернуть 0, если один или оба аргумента равны 0). Я не вижу никаких оснований жаловаться, если эллипс также является кругом, не больше, чем функция площади прямоугольника, которая должна терпеть неудачу на квадрате.

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

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

Ответ 4

Из стандарта:

  • Стандартная библиотека С++ предоставляет классы, которые будут использоваться для сообщения о некоторых ошибках (17.6.5.12) в программах на С++. В модели ошибок, отраженной в этих классах, ошибки делятся на две широкие категории: логические ошибки и ошибки времени выполнения.
  • Отличительной особенностью логических ошибок является то, что они связаны с ошибками во внутренней логике программы. Теоретически их можно предотвратить.
  • В отличие от этого, ошибки времени выполнения связаны с событиями, выходящими за рамки программы. Они не могут быть легко предсказаны заранее.

Однако все типы исключений, полученные из runtime_error, классифицируются неправильно - все они легко предотвращаются.

Для фактических ошибок времени выполнения стандартная библиотека С++ довольно несовместима, иногда она использует возвращаемые значения или внутреннее состояние (например, iostream::bad().И когда он использует исключения, они не происходят из runtime_error. Например, std::bad_alloc является прямым подклассом std::exception.

В заключение вы никогда не должны использовать std::runtime_error или любой из своих предопределенных подклассов.