Ответ 1
Контекст: я пишу серверное программное обеспечение для жизни, которое сохраняется в течение нескольких недель до загрузки следующей версии. Поэтому мои ответы могут быть связаны с очень защищенным кодом.
Принцип.
Прежде чем углубиться в особенности использования assert
, важно понять принцип, лежащий в его основе.
assert
является важным инструментом в защитном программировании. Это помогает проверять допущения (фактически утверждать их) и, таким образом, ловить ошибки программирования (отличаясь от пользовательских ошибок). Целью assert
является обнаружение ошибочных ситуаций, из которых восстановление обычно невозможно сразу.
Пример:
char const* strstr(char const* haystack, char const* needle) {
assert(haystack); assert(needle);
// ...
}
Альтернативы.
В C? Альтернативы мало. Если ваша функция не была разработана, чтобы иметь возможность передавать код ошибки или возвращать значение дозорного устройства, и это необходимо задокументировать.
В С++ исключения являются вполне приемлемой альтернативой. Тем не менее, assert
может помочь создать дамп памяти, чтобы вы могли точно видеть, в каком состоянии находится программа, в момент обнаружения ошибочной ситуации (что помогает отлаживать), в то время как исключение разворачивает стек и, таким образом, теряет контекст (невный...).
Кроме того, исключение может (к сожалению) быть пойманным обработчиком высокого уровня (или отвратительным уловом от другого разработчика (вы бы этого не сделали, конечно)), и в этом случае вы могли бы полностью пропустить ошибку до тех пор, пока она слишком поздно.
Где НЕ использовать.
Во-первых, следует понимать, что assert
всегда полезен в коде отладки. В Release определяется NDEBUG и не генерируется код. Как следствие, в Release assert
имеет то же значение, что и комментарий.
- Никогда не используйте его для проверок, необходимых для хорошего поведения программного обеспечения. Условия ошибки должны быть проверены и обработаны. Всегда.
Во-вторых, следует понимать, что неправильный ввод является частью вашей жизни. Вы хотите, чтобы ваш компилятор отображал сообщение assert
каждый раз, когда вы делали ошибку? Hum! Поэтому:
- Никогда не используйте его для проверки входных данных. Входные данные должны быть проверены, а ошибки сообщаются пользователю. Всегда.
В-третьих, следует понимать, что аварии не оценены. Ожидается, что ваша программа будет работать бесперебойно. Поэтому в режиме Release не должно возникать соблазн оставить утверждения: код выпуска заканчивается в руках конечного пользователя и никогда не должен терпеть крах. В худшем случае он должен остановиться при отображении сообщения об ошибке. Ожидается, что никакие пользовательские данные не будут потеряны во время этого процесса, и даже лучше, если после перезагрузки пользователь будет возвращен туда, где она была: это то, что делают современные браузеры, например.
- Никогда не оставляйте утверждения в Release.
Примечание: для кода сервера, после "удара" утверждения, нам удается вернуться в позицию для обработки следующего запроса в большинстве случаев.
Где его использовать.
assert
включен в режиме отладки и поэтому должен использоваться для отладки. Всякий раз, когда вы тестируете новый код, всякий раз, когда ваш тестовый пакет запускается, всякий раз, когда программное обеспечение находится в ваших руках (или ваших товарищей по команде), всякий раз, когда программное обеспечение находится в ваших руках отдела QA. Проверки позволяют обнаружить ошибки и дать полный контекст ошибки, чтобы вы могли восстановить.
- Используйте его во время циклов разработки и тестирования.
Еще лучше. Поскольку вы знаете, что код не будет выполнен в Release, вы можете позволить себе дорогостоящие проверки.
Примечание. Вы также должны протестировать двоичный файл Release, если только для проверки производительности.
И в выпуске?
Ну, в базе кода, над которой я работаю, мы заменяем недорогие утверждения (остальные игнорируются) с помощью особых исключений, которые пойманы только обработчиком высокого уровня, который будет регистрировать проблему (с обратным трассировкой), вернуть предварительно закодированный ответ об ошибке и возобновление работы службы. Команда разработчиков автоматически уведомляется.
В развернутом программном обеспечении лучшие практики, которые я видел, подразумевают создание дампа памяти и передачу его обратно разработчикам для анализа при попытке не потерять какие-либо данные пользователя и вести себя как можно более любезно к несчастному пользователю. Я чувствую себя действительно счастливым, чтобы работать на стороне сервера, когда я рассматриваю трудности этой задачи;)