Глава 11. Функции_____________________________________271

Макрос a3sert, определенный в файле assert, h, позволяет производить проверку инвариантов. Этот макрос требует логического или целочисленного аргумента — любого, который можно проверить на истинность. Истинным считается ненулевое значение, а нулевое, соответственно, ложным.

Допустим, имеется функция, копирующая строку

void CopyStringf char *dst, const char *src)

{

// Если строка нулевая, программа завершается

assert( src Т = 0) ;

dst = strdup( src) ;

}

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

В готовой программе утверждений присутствовать не должно — они включаются только для проверки и отладки. Однако нет нужды удалять их из текста программ, достаточно просто поместить перед каждой строкой, включающей заголовок assert.h, директиву препроцессора:

ftdefine NDEBUG

Совет

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

Кроме того, отладочный код не должен подменять собой нормальный контроль ошибок во время выполнения — в противном случае после отключения отладочных механизмов пользователи ваших программ останутся беззащитными. В основном проверки во время выполнения распространяются на предельные значения и тому подобные вещи. В современную доктрину защиты от ошибок также входит обработка исключительных ситуаций (exception handling), о которой можно подробнее прочитать в главе 22 "Обработка исключительных ситуаций".

Главное — не забывайте добавлять отладочный код во время написания функций. Таким образом вы сможете обрести спокойствие как за свои функции, так и за ожидаемые результаты.

Почему у функций C++ меньше аргументов

C++ является языком объектно-ориентированного программирования. Это означает, в частности, что данные и функции в классах связаны друг с другом (о чем подробнее будет рассказано в главе 15 "Перегрузка функций").