Программирование >>  Разработка устойчивых систем 

1 ... 17 18 19 [ 20 ] 21 22 23 ... 196


Трассировочные макросы

Иногда бывает удобно выводить код каждой выполняемой команды в поток 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, указал на недопустимость замены ключевых слов С++ при помощи макросов. Его замечание выглядело так: Это фязный фокус. Такие фязные фокусы иногда помогают ра.зобраться в том, почему не работает профамма, поэтому полностью отказываться от них не стоит, но не используйте их в окончательной версии профаммы .



1 ... 17 18 19 [ 20 ] 21 22 23 ... 196

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика