KnigkinDom.org» » »📕 Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

Книгу Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп читаем онлайн бесплатно полную версию! Чтобы начать читать не надо регистрации. Напомним, что читать онлайн вы можете не только на компьютере, но и на андроид (Android), iPhone и iPad. Приятного чтения!

1 ... 282 283 284 285 286 287 288 289 290 ... 337
Перейти на страницу:

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
(функция fopen() — это стандартный способ открытия файла в языке 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() и ее аналогов.

26.3.3.4. Ветвление

 

 Очевидно, что, делая выбор, мы можем принять неправильное решение. Из-за этого инструкции if и switch являются одними из основных целей для тестировщиков. Существуют две проблемы, которые необходимо исследовать.

• Все ли возможные варианты предусмотрены?

• Правильные ли действия связаны с правильными вариантами выбора?

Рассмотрим следующую бессмысленную функцию:

void do_branch1(int x, int y) // плохая функция

    // неправильное использование инструкции if

{

  if (x<0) {

    if (y<0)

      cout << "Большое отрицательное число n";

    else

      cout << "Отрицательное число n";

  }

  else if (x>0) {

    if (y<0)

      cout << "Большое положительное число n";

    else

      cout << "Положительное число n";

  }

}

Наиболее очевидная ошибка в этом фрагменте заключается в том, что мы забыли о варианте, в котором переменная x равна нулю. Сравнивая числа (положительные или отрицательные) с нулем, программисты часто забывают о нем или приписывают неправильной ветви (например, относят его к отрицательным числам). Кроме того, существует более тонкая (хотя и распространенная) ошибка, скрытая в этом фрагменте: действия при условиях (x>0 && y<0) и (x>0 && y>=0) каким-то образом поменялись местами. Это часто случается, когда программисты пользуются командами “копировать и вставить”.

Чем более сложными являются варианты использования инструкций if, тем вероятнее становятся ошибки. Тестировщики анализируют такие коды и стараются не пропустить ни одной ветви. Для функции do_branch1() набор тестов очевиден.

do_branch1(–1,–1);

do_branch1(–1, 1);

do_branch1(1,–1);

do_branch1(1,1);

do_branch1(–1,0);

do_branch1(0,–1);

do_branch1(1,0);

do_branch1(0,1);

do_branch1(0,0);

По существу, это наивный подход “перебора всех альтернатив”, которой мы применили, заметив, что функция do_branch1() сравнивает значения с нулем с помощью операторов < и >. Для того чтобы выявить неправильные действия при положительных значениях переменной x, мы должны объединить вызовы функции с желаемыми результатами.

Обработка инструкций switch аналогична обработке инструкций if.

void do_branch1(int x, int y)  // плохая функция

 // неправильное

1 ... 282 283 284 285 286 287 288 289 290 ... 337
Перейти на страницу:
Отзывы - 0

Прочитали книгу? Предлагаем вам поделится своим отзывом от прочитанного(прослушанного)! Ваш отзыв будет полезен читателям, которые еще только собираются познакомиться с произведением.


Уважаемые читатели, слушатели и просто посетители нашей библиотеки! Просим Вас придерживаться определенных правил при комментировании литературных произведений.

  • 1. Просьба отказаться от дискриминационных высказываний. Мы защищаем право наших читателей свободно выражать свою точку зрения. Вместе с тем мы не терпим агрессии. На сайте запрещено оставлять комментарий, который содержит унизительные высказывания или призывы к насилию по отношению к отдельным лицам или группам людей на основании их расы, этнического происхождения, вероисповедания, недееспособности, пола, возраста, статуса ветерана, касты или сексуальной ориентации.
  • 2. Просьба отказаться от оскорблений, угроз и запугиваний.
  • 3. Просьба отказаться от нецензурной лексики.
  • 4. Просьба вести себя максимально корректно как по отношению к авторам, так и по отношению к другим читателям и их комментариям.

Надеемся на Ваше понимание и благоразумие. С уважением, администратор knigkindom.ru.


Партнер

Новые отзывы

  1. Лена Субботина Лена Субботина28 июнь 18:28 Книга понравилась, понемногу втягиваешься в повествование,  читается легко, сюжет   интересный... Лихоимка - Надежда Храмушина
  2. Christine Christine26 июнь 01:23 ​​​​Сначала было тежеловта читать, но потом всё изменилось, я с удовольствием прочитала, спасибо за книгу. Я прочитала весь цикл... Опасное влечение - Полина Лоранс
  3. Тамаринда Тамаринда21 июнь 12:33 Редко что-то цепляет, но тут было всё живое, жизненное, чувственное, сильное, читайте, не пожалеете о своём времени...... Хрупкая связь - Ольга Джокер
Все комметарии
Новое в блоге