Под явным или неявным мы подразумеваем, что следует проверять не только формальные параметры и возвращаемое значение, но и влияние глобальных переменных, потоки ввода-вывода, файлы, распределение свободной памяти и т.д. Что же мы можем сделать? Во-первых, такая функция практически всегда бывает очень длинной, иначе ее требования и действия можно было бы описать более точно. Возможно, речь идет о функции длиной около пяти страниц или функции, использующей вспомогательные функции сложным и неочевидным способом. Для функции пять страниц — это много. Тем не менее мы видели функции намного-намного длиннее. К сожалению, это не редкость.
• Неуловимые зависимости от другого кода. Ищите использование глобальных переменных, аргументы, которые передаются не с помощью константных ссылок, указатели и т.п.
• Управление ресурсами. Обратите внимание на управление памятью (операторы new
delete), использование файлов, блокировки и т.п.• Поищите циклы. Проверьте условия выхода из них (как в функции binary_search()
• Инструкции if
switch (которые часто называют инструкциями ветвления). Ищите ошибки в их логике.Рассмотрим примеры, иллюстрирующие каждый из перечисленных пунктов.
26.3.3.1. Зависимости
Рассмотрим следующую бессмысленную функцию.
int do_dependent(int a,int& b) // плохая функция
// неорганизованные зависимости
{
int val;
cin>>val;
vec[val] += 10;
cout << a;
b++;
return b;
}
Для тестирования функции do_dependent()
cin, cout и vec. Это обстоятельство вполне очевидно в данной небольшой и бессмысленной программе, но в более крупном коде оно может быть скрыто. К счастью, существует программное обеспечение, позволяющее находить такие зависимости. К несчастью, оно не всегда доступно и довольно редко используется. Допустим, у нас нет программного обеспечения для анализа кода и мы вынуждены строка за строкой просматривать функцию в поисках ее зависимостей.Для того чтобы протестировать функцию do_dependent()
• Входные данные функции
• Значение переменной a
• Значения переменной b
int, на которую ссылается переменная b. • Ввод из потока cin
val) и состояние потока cin. • Состояние потока cout
• Значение переменной vec
vec[val].• Выходные данные функции
• Возвращаемое значение.
• Значение переменной типа int
b (мы ее инкрементировали). • Состояние объекта cin
• Состояние объекта cout
• Состояние массива vec
vec[val]). • Любые исключения, которые мог сгенерировать массив vec
vec[val] может находиться за пределами допустимого диапазона).