Вход/Регистрация
Программирование. Принципы и практика использования C++ Исправленное издание
вернуться

Страуструп Бьерн

Шрифт:

void do_resources2(int a, int b, const char* s) // менее плохой код

{

ifstream is(s); // открываем файл

vector<int>v1(a); // создаем вектор (выделяем память)

if (b<=0) throw Bad_arg; // может генерировать исключение

vector<int> v2(b); // создаем другой вектор (выделяем память)

}

Теперь каждый ресурс принадлежит объекту и освобождается его деструктором. Иногда, чтобы выработать идеи для тестирования, полезно попытаться сделать функцию более простой и ясной. Общую стратегию решения задач управления ресурсами обеспечивает метод RAII (Resource Acquisition Is Initialization — получение ресурса есть инициализация), описанный в разделе 19.5.2.

Отметим, что управление ресурсами не сводится к простой проверке, освобожден ли каждый выделенный фрагмент памяти. Иногда мы получаем ресурсы извне (например, как аргумент), а иногда сами передаем его какой-нибудь функции (как возвращаемое значение). В этих ситуациях довольно трудно понять, правильно ли распределятся ресурсы. Рассмотрим пример.

FILE* do_resources3(int a, int* p, const char* s) // плохая функция

// неправильная передача ресурса

{

FILE* f = fopen(s,"r");

delete p;

delete var;

var = new int[27];

return f;

}

Правильно ли, что функция

do_resources3
передает (предположительно) открытый файл обратно как возвращаемое значение? Правильно ли, что функция
do_resources3
освобождает память, передаваемую ей как аргумент
p
? Мы также добавили действительно коварный вариант использования глобальной переменной var (очевидно, указатель). В принципе передача ресурсов в функцию и из нее является довольно распространенной и полезной практикой, но для того чтобы понять, корректно ли выполняется эта операция, необходимо знать стратегию управления ресурсами. Кто владеет ресурсом? Кто должен его удалять/освобождать? Документация должна ясно и четко отвечать на эти вопросы. (Помечтайте.) В любом случае передача ресурсов изобилует возможностями для ошибок и представляет сложность для тестирования.

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

26.3.3.3. Циклы

Мы уже рассматривали циклы, когда обсуждали функцию
binary_search
.

Большинство ошибок возникает в конце циклов.

• Правильно ли проинициализированы переменные в начале цикла?

• Правильно ли заканчивается цикл (часто на последнем элементе)?

Приведем пример, который содержит ошибку.

int do_loop(const vector<int>& v) // плохая функция

// неправильный цикл

{

int i;

int sum;

while(i<=vec.size) sum+=v[i];

return sum;

}

Здесь содержатся три очевидные ошибки. (Какие именно?) Кроме того, хороший тестировщик немедленно выявит возможности для переполнения при добавлении чисел к переменной

sum
.

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

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

char buf[MAX]; // буфер фиксированного объема

char* read_line // опасная функция

{

int i = 0;

char ch;

while(cin.get(ch) && ch!='\n') buf[i++] = ch;

buf[i+1] = 0;

return buf;

}

Разумеется, вы не написали бы ничего подобного! (А почему нет? Что плохого в функции

read_line
?) Однако эта ошибка, к сожалению, является довольно распространенной и имеет разные варианты.

// опасный фрагмент

gets(buf); // считываем строку в переменную buf

scanf("%s",buf); // считываем строку в переменную buf

Поищите описание функций
gets
и
scanf
в своей документации и избегайте их как чумы. Под словом “опасная” мы понимаем, что переполнение буфера является инструментом для взлома компьютеров. В настоящее время реализации выдают предупреждение об опасности использования функции
gets
и ее аналогов.

  • Читать дальше
  • 1
  • ...
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: