|
Программирование >> Разработка устойчивых систем
Трассировочные макросы Иногда бывает удобно выводить код каждой выполняемой команды в поток cout или в трассировочный файл. Вот как выглядит препроцессорный макрос для решения этой задачи: #define TRACE(ARG) cout #ARG endl: ARG size t 1: for (i = 0: i < name.SizeO: ++i) *osptr *=: *osptr = endl: for (i = 0: i < tests.size(): ++i) { assert(tests[i]): totFail += tests[i]->report(); *OSptr ======= ; for (i = 0: i < name.sizeO: ++i) *osptr : *osptr = endl: return totFail: else return getNumFailedO: long Suite::getNumPassedO const ( long totPass = 0: for (size t i = 0: i < tests.sizeO: ++i) ( assert(tests[i]): totPass += tests[i]->getNumPassed(): return totPass: long Suite::getNumFailed() const { long totFail =0: for (size t i = 0: i < tests.size(): ++i) ( assert(tests[i]): totFail += tests[i]->getNumFailed(); return totFail: void Suite::resetО { for (size t i = 0: i < tests.sizeO: ++i) { assert(tests[i]); tests[i]->reset(): } /:- Мы будем использовать систему TestSuite там, где это будет уместно. Методика отладки Утверждения, о которых рассказывалось в начале этой главы, приносят огромную пользу при отладке; они помогают обнаружить логические ошибки до того, как те принесут реальный вред. В этом разделе собраны полезные советы и приемы, применяемые в процессе отладки. Трассировочный файл ВНИМАНИЕ --- Программный код, приведенный в этом и следующем разделах, не соответствует официальному стандартному языку С++. В частности, мы переопределяем cout и new с применением макросов; малейшая неосторожность приведет к удивительным последствиям. Тем не менее примеры работали на всех компиляторах, используемых нами, и поставляли полезную информацию. Это единственное место в книге, где мы отклоняемся от священных канонов программирования по Стандарту . Учтите, что для работы этих приемов необходимо объявление using, чтобы имя cout не снабжалось префиксом пространства имен; иначе говоря, stdiicout работать не будет. Следующая программа создает трассировочный файл и отправляет в него весь вывод, который в обычных условиях передается в cout. Все, что для этого нужно, - вставить в программу директиву #define TRACEON и включить заголовочный файл (конечно, с таким же успехом можно просто включить две ключевые строки прямо в файл): : C03:Trace.h Создание трассировочного файла #ifndef TRACE H #def1ne TRACE H #1 ncl ude <fstreani> #ifdef TRACEON ofstream TRACEFILE ( TRACE.OUT ); Остается лишь заключить трассируемые команды в этот макрос. Впрочем, при этом могут возникнуть проблемы. Для примера возьмем следующий цикл: fordnt 1 = 0: 1 < 100; 1++) cout 1 endl; Каждая строка заключается в макрос TRACE(): TRACE(for(int 1 = 0; 1 < 100; 1++)) TRACE( cout 1 endl); После расширения будет получен следующий результат: cout fordnt 1 = 0; 1 < 100; i++) endl ; fordnt 1 = 0; 1 < 100; 1++) cout cout 1 endl; endl; cout i endl; He совсем то, что требовалось. А значит, при использовании этого приема необходима осторожность. Ниже приведена другая разновидность макроса TRACE: #def1ne D(a) cout #a =[ a ] endl; При вызове макроса D передается выражение, которое требуется вывести. Макрос выводит это выражение, а за ним - вычисленное значение (предполагается, что для типа результата существует перегруженный оператор ). Например, вызов может выглядеть так: D(a+b). Используйте макрос D для проверки промежуточных результатов. Эти два макроса реализуют две основные операции, выполняемые в процессе отладки: трассировку программного кода и вывод значений. Хороший отладчик значительно повышает эффективность труда программиста, но иногда отладчик недоступен или им может быть неудобно пользоваться в конкретной ситуации. Приемы, описанные в этом разделе, работают всегда. #def1ne cout TRACEFILE #end1f #end1f TRACE H III:- Простая тестовая программа для этого файла выглядит так: : C03:Tracetst.cpp {-Ьог} #include <1ostreani> #inc1ude <fstreani> #1nc1ude ../require.h using namespace std: #def1ne TRACEON #1nclude Trace.h int mainO ( ifstream f( Tracetst.cpp ): assureCf. Tracetst.cpp ): cout f.rdbufO: Вывод содержимого файла в трассировочный файл } III:- Поскольку Trace.h заменяет имя cout на уровне исходного текста, все команды вывода в cout в вашей программе теперь направляют информацию в трассировочный файл. В частности, это позволяет сохранить выходные данные программы в файле, если в операционной системе отсутствуют нормальные средства перенаправления вывода. Поиск утечки памяти Следующие тривиальные приемы отладки рассматривались в первом томе книги. Чтобы организовать автоматическую проверку индекса для массива любого типа, воспользуйтесь шаблоном Array из примера С16:Аггау3.срр. Когда все будет готово к построению окончательной версии программы, проверку можно отключить для повышения эффективности (впрочем, остаются проблемы с получением указателя на массив). Проверьте невиртуальные деструкторы в базовых классах. К числу стандартных проблем с памятью относятся ошибочный вызов оператора delete для памяти, не находящейся в куче; повторное удаление памяти в куче; и самое частое - неудаленный указатель. В этом разделе рассматривается система, которая помогает отслеживать подобные ошибки. Дополнительное предупреждение (к тому, о чем говорилось в предыдущем разделе): наш способ перегрузки оператора new может не работать на некоторых платформах. Кроме того, он функционирует только в программах, не вызывающих операторную функцию operator new() напрямую. В этой книге мы стремились представлять только те программы, которые полностью соответствуют стандартному языку С++, однако в данном случае было сделано исключение по следующим причинам. Хотя эта методика является технически незаконной , она работает во многих компиляторах. Попутно демонстрируются некоторые полезные приемы. Наш главный технический рецензент, Пит Бекер (Pete Becker) из Dinkumware. Ltd, указал на недопустимость замены ключевых слов С++ при помощи макросов. Его замечание выглядело так: Это фязный фокус. Такие фязные фокусы иногда помогают ра.зобраться в том, почему не работает профамма, поэтому полностью отказываться от них не стоит, но не используйте их в окончательной версии профаммы .
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |