Используйте исключения для сигнализации о невозможности выполнить требуемую задачу
Причина
Не должно быть возможности игнорировать ошибку, поскольку это может оставить систему или вычисление в неопределённом (или неожиданном) состоянии. Это основной источник ошибок.
Пример
int printf(const char* ...); // плохо: возвращает отрицательное число при ошибке вывода
template<class F, class ...Args>
// хорошо: бросает system_error, если не удаётся запустить новый поток
explicit thread(F&& f, Args&&... args);
Примечание
Что такое ошибка?
Ошибка означает, что функция не может достичь своей заявленной цели (включая установку постусловий). Вызывающий код, игнорирующий ошибку, может привести к неверным результатам или неопределённому состоянию системы. Например, невозможность подключиться к удалённому серверу сама по себе не является ошибкой: сервер может отказывать в подключении по разным причинам, поэтому естественным является возврат результата, который вызывающая сторона всегда должна проверять. Однако если сбой при установлении соединения считается ошибкой, то при сбое следует бросить исключение.
Исключение
Многие традиционные функции интерфейса (например, обработчики сигналов UNIX) используют коды ошибок (например, errno) для сообщения о том, что на самом деле является кодами состояния, а не ошибками. У вас нет хорошей альтернативы их использованию, поэтому их вызов не нарушает правило.
Альтернатива
Если вы не можете использовать исключения (например, потому что ваш код содержит много старых сырых указателей или существуют жёсткие ограничения реального времени), рассмотрите использование стиля, возвращающего пару значений:
int val;
int error_code;
tie(val, error_code) = do_something();
if (error_code) {
// ... обрабатываем ошибку или выходим ...
}
// ... используем val ...
Этот стиль, к сожалению, приводит к неинициализированным переменным. Начиная с C++17 функциональность «структурированных привязок» позволяет инициализировать переменные непосредственно из возвращаемого значения:
auto [val, error_code] = do_something();
if (error_code) {
// ... обрабатываем ошибку или выходим ...
}
// ... используем val ...
Примечание
Мы не считаем «производительность» веским аргументом против использования исключений.
- Часто явная проверка ошибок и их обработка потребляют столько же времени и памяти, сколько обработка исключений.
- Зачастую более чистый код даёт лучшую производительность с исключениями (упрощая трассировку путей через программу и их оптимизацию).
- Хорошее правило для кода, критичного по производительности, — выносить проверки за пределы критической части кода.
- В долгосрочной перспективе более регулярный код лучше оптимизируется.
- Всегда тщательно измеряйте перед тем, как делать заявления о производительности.
Смотрите также: I.5 и I.7 для сообщения о нарушениях предусловий и постусловий.
Контроль
- (Не применяется) Это философский руководящий принцип, нецелесообразный для прямой проверки.
- Искать
errno.