Программирование >>  Операторы преобразования типа 

1 ... 92 93 94 [ 95 ] 96 97 98 ... 239


#lnclLide <vector> #inc1ude <algor1thm> using namespace std:

Обьект функции для вычисления среднего арифметического class MeanValue ( private:

long num: Счетчик элементов long sum: Сумма всех значений элементов public: Конструктор

MeanValue () : num(O). sum(O) { }

Вызов функции

- обработка очередного элемента последовательности void OperatorO (int elem) (

num++; Увеличение счетчика

sum += elem; Прибавление значения

Возвращение среднего арифметического double value () {

return stat1c cast<double>Csum) / static cast<double>(num);

1nt mainO (

vector<lnt> coll:

Вставка элементов от 1 до 8 for (int i=l; i<=8: ++1) { coll.push back(i);

Вычисление и вывод среднего арифметического MeanValue mv = for each (coll .beginO. coll.endO. Интервал

MeanValueO); Операция

cout mean value: mv.valueO endl;

Вызов MeanValueO создает объект функции, который подсчитывает количество элементов и вычисляет сумму их значений. Передача этого объекта при вызове for each() обеспечивает его вызов для каждого элемента контейнера соН;

MeanValue mv = for each (coll.beginO. coll.endO.

MeanValueO);



Объект функции, возвращенный алгоритмом for each(), присваивается mv, поэтому после вызова можно запросить информацию о его состоянии в виде mv.value(). В итоге программа выводит следующий результат:

mean value: 4.5

Класс MeanValue можно дополнительно усоверщенствовать, определив автоматическое преобразование к типу double. В этом случае среднее арифметическое, вычисленное for each(), можно будет напрямую использовать в программе. Пример такого рода приведен на с. 335.

Предикаты и объекты функций

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

fo.removeif.срр Unclude <1ostream> Unclude <l1st> Unclude <algor1thm> Iinclude print.hpp using namespace std;

class Nth (, Объект функции возвращает true для n-го вызова

private:

1nt nth; Номер вызова, для которого следует вернуть true

int count: Счетчик вызовов public:

Nth (int n) : nth(n). count(O) ( }

bool OperatorO (int) { return ++count == nth:

int mainO (

list<int> col 1:

Вставка элементов со значениями от 1 до 9 for (int i=l; i<=9: ++i) ( coll.push back(i):

PRINT ELEMENTS(coll. coll: ):

Удаление третьего элемента list<int>::iterator pos:



pos = removejf(coll .beginO .col 1 .endO. Интервал

Nth(3)): Критерий удаления

coll .erase(pos.coll .endO);

PRINT ELEMENTS(coll. nth removed: );

Программа определяет объект функции Nth, который возвращает true для каждого п-го вызова. Но если передать этот объект алгоритму removejf(), выполняющему удаление всех элементов, для которых унарный предикат возвращает true (см. с. 371), вас ждет сюрприз:

coll: 12 3 4 5 6 7 8 9

nth removed: 12 4 5 7 8 9

Из коллекции удаляются два элемента, третий и шестой. Дело в том, что обычная реализация алгоритма создает внутреннюю копию предиката:

template <class ForwIter. class Predlcate> Forwiter std: .remove 1f(ForwIter beg, ForwIter end.

Predicate op)

beg = f1nd 1f(beg. end. op): lf (beg == end) ( return beg;

else (

ForwIter next = beg;

return remove copy 1f(++next. end. beg. op);

Для поиска первого удаляемого элемента алгоритм использует find if(), но затем для обработки оставшихся элементов используется копия переданного предиката ор. Объект функции Nth возвращается к прежнему состоянию и удаляет третий элемент из оставшихся (то есть шестой элемент коллекции).

Такое поведение не является ошибкой. Стандарт не ограничивает внутреннее копирование предиката в алгоритме. Таким образом, для надежной работы алгоритмов стандартной библиотеки С++ не следует передавать объект функции, поведение которого зависит от частоты его копирования или вызова. Иначе говоря, если унарный предикат вызывается с одинаковыми аргументами, то он всегда должен возвращать один и тот же результат. Вызов не должен изменять внутреннее состояние предиката, а копия предиката должна иметь точно такое же состояние, как оригинал. Чтобы состояние предиката не изменялось при вызове функции, оператор () рекомендуется объявлять в виде чконстантной функции.

В принципе это странное поведение можно обойти и обеспечить нормальную работу алгоритма даже с такими объектами функций, как Nth, без сниже-



1 ... 92 93 94 [ 95 ] 96 97 98 ... 239

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