Re: Набор исключений метода
От: so5team https://stiffstream.com
Дата: 16.06.18 07:04
Оценка: 30 (3) +2
Здравствуйте, developer, Вы писали:

D>Стоит ли использовать исключения, которые не унаследованы от std::exception?


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

D>Стоит ли наследовать все исключения от какого-то одного класса, например, от std::runtime_error — чтобы иерархия исключений имела один единственный корень?


Да. Например, делаете my_exception наследником std::exception (или std::runtime_error, если хотите), а уже от my_exception наследуете остальные свои классы исключений.

D>Стоит ли как-то сгруппировать исключения в группы (т.е. для каждого метода своя группа исключений)?


Зависит, как минимум, от двух вещей:

1. Объем вашей кодовой базы и ее разделение на более-менее независимые модули. Если у вас небольшая кодовая база и ярко выраженных модулей нет, то можно обойтись всего одним классом исключения. Если кодовая база большая (скажем от 50-100KLOC и больше) и есть модули, отвечающие за разную функциональность (скажем, модуль net для работы с сетью, db для работы с СУБД, crypto для криптографии и т.д.), то для каждого модуля можно сделать свой базовый класс исключения. Тогда будет проще фильтровать проблемы, относящиеся к конкретному модулю. Что-то вроде:
try {
  auto raw_data = net::recv_msg(channel);
  auto data = crypto::decrypt_msg(raw_data);
  ...
}
catch(const crypto::exception & x) {
  ... // Специальным образом обрабатываем ошибки дешифрации.
}

При этом у вас может быть вот такая иерархия исключений:
std::exception
`- my_exception
   `- net::exception
   |  `- ...
   `- crypto::exception
      `- ...
...


2. Если вам нужно сгруппировать в исключениях какие-то наборы данных, описывающих ошибку. Например, в каких-то случаях вам нужно передавать в исключении имя файла и код системной ошибки. В каких-то случаях имя пользователя и причину невозможности его аутентификации. В каких-то случаях недопустимый индекс и актуальный разрешенный диапазон индексов. Вот если у вас такие случаи есть, то тогда вы можете создавать отдельные ветки иерархии исключений:
std::exception
`- my_exception
   `- file_error (name, error_code)
   |  `- open_file_error
   |  `- read_file_error
   |  `- unlink_error
   |  ...
   `- user_auth_error (user_name, reason)
      `- unknown_user_error
      `- no_permission_error
      `- disabled_user_error
      `- ...


D>Иногда бывает одинаково уместно или вернуть false или кинуть исключение — что предпочесть?


В таких случаях ориентируются на три важнейших фактора:

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

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

Однако, в современном мире для таких случаев может быть выгоднее использовать специализированные классы вроде folly::Expected или outcome::result.

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