File
, в одной-единственной функции Filе::Write(const char*buffer, size_t size)
, которая требует, чтобы файл был открыт для записи, а указатель buffer
имел ненулевое значение, вы можете предпринимать следующие действия.
•
•
•
std::vector
предоставляет два пути для выполнения индексированного доступа: оператор operator[]
, который не выполняет проверок выхода за пределы диапазона, и функцию at
, которая такую проверку выполняет. И оператор operator[]
, и функция at
требуют выполнения предусловия, состоящего в том, что аргумент не должен выходить за пределы диапазона. Поскольку от оператора operator[]
не требуется проверка его аргумента, должно быть четко документировано, что вызывающий код отвечает за то, чтобы аргумент оператора находился в допустимом диапазоне значений; понятно, что данная функция небезопасна. Функция же at
в той же ситуации вполне безопасна, поскольку документировано, что она проверяет принадлежность своего аргумента к допустимому диапазону значений, и если аргумент выходит за пределы допустимого диапазона значений, то она сообщает об ошибке (путем генерации исключения std::out_of_range)
.
71. Проектируйте и пишите безопасный в отношении ошибок код
В каждой функции обеспечивайте наиболее строгую гарантию безопасности, какой только можно добиться без дополнительных затрат со стороны вызывающего кода, не требующего такого уровня гарантии. Всегда обеспечивайте, как минимум, базовую гарантию безопасности.
Убедитесь, что при любых ошибках ваша программа всегда остается в корректном состоянии (в этом и заключается базовая гарантия). Остерегайтесь ошибок, нарушающих инвариант (включая утечки, но не ограничиваясь ими).
Желательно дополнительно гарантировать, что конечное состояние либо является исходным состоянием (в результате отката после происшедшей ошибки), либо корректно вычисленным целевым состоянием (если ошибок не было). Это — строгая гарантия безопасности.
Еще лучше гарантировать, что сбой в процессе операции невозможен. Хотя для большинства функций это невозможно, такую гарантию следует обеспечить для таких функций, как деструкторы и функции освобождения ресурсов. Данная гарантия — гарантия бессбойности.
Базовая, строгая гарантии и гарантия бессбойности (известная также как гарантия отсутствия исключений) впервые были описаны в [Abrahams96] и получили широкую известность благодаря публикациям [GotW], [Stroustrup00, §E.2] и [Sutter00], посвященным вопросам безопасности исключений. Эти гарантии применимы к обработке любых ошибок, независимо от конкретного использованного метода, так что мы можем воспользоваться ими при описании безопасности обработки ошибок в общем случае. Гарантия бессбойности является строгим подмножеством строгой гарантии, а строгая гарантия, в свою очередь, является строгим подмножеством базовой гарантии.
В общем случае каждая функция должна обеспечивать наиболее строгую гарантию, которую она в состоянии обеспечить без излишних затрат для вызывающего кода, которому не требуется такая степень гарантии. Там, где это возможно, следует дополнительно обеспечить достаточную функциональность для того, чтобы требующий более строгую гарантию код мог получить ее (см. в примерах к данной рекомендации случай vector::insert
).
В идеале следует писать функции, которые всегда успешно выполняются и, таким образом, могут обеспечить гарантию бессбойности. Некоторые функции должны всегда обеспечивать такую гарантию, в частности, деструкторы, функции освобождения ресурсов и функции обмена (см. рекомендацию 51).