Программирование >>  Дополнительные возможности наследования 

1 ... 219 220 221 [ 222 ] 223 224 225 ... 265


Чтобы не зависеть от конкретной версии компилятора, т.е. от его реакции на макрос assert О, можно написать собственный вариант этого макроса. В листинге 21.4 содержится простой макрос assertO и показано его использование.

Аистииг 21.4. ПростсО макрос assertO

2 3 4 5 6 7 8 9

10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27

Листинг 21.4. Макрос ASSERT #define DEBUG #include <iostream.h>

#ifndef DEBUG

#define ASSERT(x) #else

ffdefine ASSERT(x) \ if (! (X)) \

{ \

cout << ERROR!! Assert << ffx failed\ n ; \

cout << on line << LINE Л n ; \

cout << in file FILE \ n ; \

#endif

int main() {

int X = 5;

oout Первый макрос assert: \ n ; ASSERT(x==5);

cout \ пВторой макрос assert: \ n ASSERT(x != 5); oout << \ пВыполнено.\ n ; return 0;

First assert:

Second assert: ERROR!! Assert x !=§ failed on line 24

in file t8St1704.opp Done.

В строке 2 определяется лексема DEBUG. Обычно это делается из командной строки (или в интегрированной среде разработки) во время компиляции, что позволяет управлять этим процессом. В строках 8-14 определяется макрос assertO. Как правило, это делается в файле заголовка ASSERT, 1прр, который следует включить во все файлы источников,

В строке 5 проверяется определение лексемы DEBUG. Если она не определена, макрос assertO определяется таким образом, чтобы вообще не создавался никакой код. Если же лексема DEBUG определена, то выполняются строки кода 8-14.



Сам макрос assert() представляет собой цельное выражение, разбитое на семь строк исходного кода. В строке 9 проверяется значение, переданное как параметр. Если передано значение FALSE, выводится сообшение об ошибках (строки 11 - 13). Если передано значение TRUE, никакие действия не выполняются.

Отладка программы с помощью макроса asscrtO

Многие ошибки допускаются профаммистами, поскольку они верят в то, что функция возвратит определенное значение, а указатель будет ссылаться на обьект, так как это логически очевидно, и забывают о том, что компилятор не подчиняется человеческой логике, а слепо следует командам и инструкциям, даже если они противоречат всякой логике. Программа может работать самым непонятным образом из-за того, что вы забыли инициализировать указатель при объявлении, и поэтому он ссылается на случайные данные, сохранившиеся в связанных с 1шм ячейках памяти. Макрос assert()пoмoжeт в поиске ошибок такого типа при условии, что вы научитесь правильно использовать этот макрос в своих программах. Каждый раз, когда в программе указатель передается как парамеф или в виде возврата функции, имеет смысл проверить, действительно ли этот указатель ссылается на рсшП)Иое значение, В любом месте профаммы, если ее выполнение зависит от значения некоторой переменной, с помощью макроса assertO вы сможете убеди(ься в том. тго на это значение можно полагаться.

При этом от частого использования макроса a;:,s ii() вы не несете никаких убытков, поскольку он антомагически удаляется из профаммы, если не будет определена лексема DEBUG, Более toio, присутствие макроса также обеспечивает хорошее

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

Макрос assertO вместо исключении

На процглом занятии вы узнали, как с помоии,ю исюиочеиий можно отслеживать и обрабатывать аварийные ситуаи.ии, Г?ажио !пм( гить, что макрос assertO не предназначен для обработки таких исюиочительрп,1Х ситуаций, как ввод ошибочных данных, нехватка памяти, невозможность открыть файл и т.д, которые возникают во время выполнения профаммы. Макрос assonO создан для отслеживания логических и синтаксических ошибок программирования. Следовательно, если макрос assertO срабатывает, это сигнализирует об ошибке непосредственно в коде программы.

Важно понимать, что при передаче профаммы заказчика.м макросы assertO в коде будут удалены. Поэтому если с ошибками выполнения профа.ммы удавалось справляться только благодаря макросу asscri (), то у заказчика эта профамма просто не будет работать.

Распространенной ошибкой является использование макроса assertO для тестирования возвращаемого значения при выполнении операции выделения памяти:

Animal *pCat = new Cat:

Assert(pCat); неправильное использование гиакроса pCat->SomeFunction();

Это пример классической ошибки при отладке программы. В данном случае профаммист пытается с помошью макроса a.ssertO предупредить возникновение исключительной ситуации нехватки свободной памяти. Обычно профаммист тестирует профамму на компьютере с достаточным объемом памяти, поэтому макрос assert()B этом месте профаммы никогда не сработает. У заказчика может быть устаревшая версия компьютера, поэтому, когда программа доходит до этой точки, обращение к оператору



new терпит крах и программа возвращает NULL (пустой указатель). Однако макроса assertO больше нет в коде, и некому сообщить пользователю о том, что указатель ссылается на NULL. Поэтому, как только дойдет очередь до выражения pCat->SomeFunction(), программа дает сбой.

Возвращение значения NULL при вьщеления памяти - это не ошибка профаммирования, а исключительная ситуация. Чтобы профамма смогла с честью выйти из этой ситуации, необходимо использовать исключение. Помните, что макрос assertO полностью удаляется из профаммы, если лексема DEBUG не определена. (Исключения были подробно описаны на занятии 20.)

ПоОочные эффекты

Нередко случается так, что ошибка проявляется только после удаления экземпляров макроса assertO. Почти всегда это происходит из-за того, что профамма попадает в зависимость от побочных эффектов, вызванных выполнением макроса assertO или другими частями кода, используемыми только для отладки. Например, если записать

ASSERT (х = 5)

при том, что имелась в виду проверка х == 5, вы тем самым создадите чрезвычайно противную ошибку.

Предположим, что как раз до выполнения макроса assertO вызывалась функция, которая установила переменную х равной 0. Используя данный макрос, вы полагали, что выполняете проверку равенства переменной х значению 5. На самом же деле вы устанавливаете значение х равным 5. Тем не менее эта ложная проверка возвращает значение TRUE, поскольку выражение х = 5 не только устанавливает переменную х равной 5, но одновременно и возвращает значение 5, а так как 5 не равно нулю, то это значение расценивается как истинное.

Во время отладки программы макрос assertO не выполняет проверку равенства переменной X значению 5, а присваивает ей это значение, поэтому профамма работает прекрасно. Вы готовы передать ее заказчику и отключаете отладку. Теперь макрос assertO удаляется из кода и переменная х не устанавливается равной 5. Но поскольку в результате ошибки в функции переменная х устанавливается равной О, профамма дает сбой.

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

Инварианты класса

Для многих классов существует ряд условий, которые всегда должны выполняться при завершении работы с функцией-членом класса. Эти обязательные условия выполнения класса называются инвариантами класса. Например, обязательными могут быть следующие условия: объект CIRCLE никогда не должен иметь нулевой радиус или объект ANIMAL всегда должен иметь возраст больше нуля и меньше 100.

Может быть весьма полезным объявление метода Invariants(), который возвращает значение TRUE только в том случае, если каждое из этих условий является истинным. Затем можно вставить макрос ASSERT(Invariants()) в начале и в конце каждого



1 ... 219 220 221 [ 222 ] 223 224 225 ... 265

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