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

Исключение против кода ошибки против assert

Я работаю над библиотекой, которая генерирует отчеты об устройствах. Функция члена generate_report (const std::string& no) может выйти из строя по различным причинам:

  • неверный отчет
  • неверное состояние (report_generator - FSM)
  • неактивное устройство
  • ошибка при создании отчета

Какой механизм обработки ошибок лучше всего подходит для этих ошибок?

  • просто верните true или false
  • код ошибки возврата
  • assert и log
  • throw exception (s)
  • любая комбинация указанных выше

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

EDIT: Спасибо за ответы до сих пор! Для меня теперь ясно, когда использовать утверждения и когда делать обработку ошибок. Что касается обработки ошибок, то коды ошибок и исключения имеют как плюсы, так и минусы. Я думаю, что я исхожу за исключения (и создаю четыре класса для вышеупомянутых ошибок), но я еще не уверен. Я всегда думал об исключениях из "неожиданных ситуаций". Недействительный отчет no не является неожиданным. Любой совет?:)

4b9b3361

Ответ 1

Любые из них имеют разные цели:

  • код ошибки vers. Исключение (исключения): исключения и коды ошибок представляют разные идиомы, как обрабатывать кривые кодов результатов. Исключения более надежны - коды результатов могут быть проигнорированы или потеряны. Библиотека обычно должна четко различать, где/какие исключения выбрасываются, и когда используются коды ошибок. В лучшем случае используйте только один из них.

  • return true или false: специализация кодов ошибок. Обычно худшая идея - только хорошая, если больше нечего сообщать, чем хорошее или плохое (т.е. malloc возвращает либо хорошее, либо плохое (= NULL).

  • assert и log: это методы отладки и не должны использоваться в качестве механизмов отчетов для пользователей/клиентов. Утверждает только сказать "что-то случилось, что я не могу справиться - я ушел".

Ответ 2

assert не является правильным выбором. Используйте assert, когда у вас есть инвариант; чего никогда не должно было случиться. Не делайте такие вещи, как assert(), что аргумент никогда не будет null, если это условие ошибки, а не инвариант.

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

Ответ 3

Исключения по сравнению с истинными/ложными и кодами ошибок имеют несколько важных преимуществ:

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

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

Ответ 4

Я рекомендую прочитать сообщество Boost guide [boost.org] для исключений и обработки ошибок.

Ответ 5

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

Ответ 6

Насколько надежны устройства, о которых вы сообщаете?

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

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

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

На самом деле не имеет значения, что mutch как "исключения" действительно просто причудливый способ кодирования "if (x!= 0) {goto error_routine; }, но я лично предпочитаю обработку исключений для обработки исключительных ситуаций, а не обычных событий, таких как end_of_file.

Ответ 7

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

Итак, я бы закодировал библиотеку исключений С++ и предоставил файлы заголовков, описывающие ваши классы исключений. Я бы также закодировал интерфейс C, который обрабатывает исключения для пользователя. Теперь пользователь может ссылаться на какой-либо интерфейс:

#ifdef __cplusplus__
void generate_report(const std::string& rep_number, ostream& output);

extern "C" 
#endif
int generate_report(const char* rep_number, const char* outputfilename,
                    int* error_code, char* error_text, int max_error_text_len);

Реализация C вызывает реализацию С++:

extern "C" 
int generate_report(const char* rep_number, const char* outputfilename,
                    int* error_code, char* error_text, int max_error_text_len)
{
    ofstream os;
    try {
        os.open(outputfilename, IOS_WRITE);
        generate_report(rep_number, os);
        os.close();
        return TRUE;
    } catch (base_exception& e) {
        os.close();
        if (error_code) *error_code = e.error_code();
        if (error_text) strncpy(error_text, e.str(), max_error_text_len);
        return FALSE;
    }
}

Ответ 8

Сначала - будьте последовательны!

Во-вторых:

  • просто true/false недостаточно. Он должен сочетаться с кодами ошибок (например, false + getLastError).
  • коды ошибок бывают быстрыми, но создайте некоторую инфраструктуру, чтобы легко конвертировать их в строки.
  • assert/log: no, вы хотите, чтобы приложение могло реагировать на ошибку
  • исключения медленнее, чем коды ошибок, но легче программировать с помощью сложного потока управления.
  • : только true/false + коды ошибок объединяются, для остальных BE CONSISTENT, что означает: не объединяйтесь.

Ответ 9

  • вести журнал следует использовать, если у вас нет доступа к терминалу для создания отчетов об ошибках чтения/чтения.
  • возврат True/False должен сочетаться с кодами ошибок. Пример: функция возвращает True при успешном завершении, False при ошибке и устанавливает переменную (глобальную или параметр, ваш выбор) с соответствующим кодом ошибки/описанием.
  • Исключения: на мой взгляд, хорошо сочетать их с протоколированием и грациозным восстановлением от ошибок. Если это невозможно, вы можете также прибегать к кодам ошибок, поскольку исключения не предоставляют никаких дополнительных преимуществ.
  • assert(): Как указывали другие, он компилируется на сборках релизов, поэтому огонь по своему усмотрению.