Программирование >>  Включение нужных заголовков 

1 ... 43 44 45 [ 46 ] 47 48 49 ... 71


ее копию - см. совет 38). Что еще важнее, переданная (и позднее возвращаемая) функция может обладать побочными эффектами.

Помимо побочных эффектов между f oreach и accumul ate существуют два основных различия. Во-первых, само название accumul ate ассоциируется с вычислением сводного значения по интервалу, а название for each скорее предполагает выполнение некой операции с каждым элементом интервала. Алгоритм for each может использоваться для вычисления сводной величины, но такие решения по наглядности уступают accumul ate.

Во-вторых, accumulate непосредственно возвращает вычисленное значение, а f or each возвращает объект функции, используемый для дальнейшего получения информации. В С++ это означает, что в класс функтора необходимо включить функцию для получения искомых данных.

Ниже приведен предыдущий пример, в котором вместо accumul ate используется for each:

struct Point{...]; См. ранее

class PointAverage:

public unary function<Point,void>{ См. совет 40

public:

PointAverage():xSum(0).ySum(0),numPoints(0) {}

void operatorO (const Point& p)

++numPoints; xSum += p.x; ySum += p.y:

Point resul to const {

return PointCxSum/numPoints.ySum/numPoints);

private: si2e t numPoints: double xSum: double ySum:

list<Point> Ip:

Point avg = for each(lp.begin(),lp.end(),PointAverageO).result():

Лично я предпочитаю обобщать интервальные данные при помощи accumul ate, поскольку мне кажется, что этот алгоритм наиболее четко передает суть происходящего, однако foreach тоже работает, а вопрос побочных эффектов для for each не так принципиален, как для accumul ate. Словом, для обобщения интервальных данных могут использоваться оба алгоритма; выберите тот, который вам лзше подойдет.

Возможно, вас интересует, почему у for each параметр-функция может иметь побочные эффекты, а у accumul ate - не может? Представьте, я бы тоже хотел это знать. Что ж, дорогой читатель, некоторые тайны остаются за пределами наших познаний. Чем accumul ate принципиально отличается от for each? Пока я еще не слышал убедительного ответа на этот вопрос.



функции, функторы и классы функций

Нравится нам это или нет, но функции и представляющие их объекты (функторы) занимают важное место в STL. Они используются ассоциативными контейнерами для упорядочения элементов, управляют работой алгоритмов типа find if, конструкции for each и transform без них теряют смысл, а адаптеры типа notl и Ы nd2nd активно создают их.

Да, функторы и классы функторов встречаются в STL на каждом шагу. Встретятся они и в ваших программах. Умение создавать правильно работающие функторы абсолютно необходимо для эффективного использования STL, поэтому большая часть этой главы посвящена одной теме - как добиться того, чтобы функторы работали именно так, как им положено работать в STL. Впрочем, один совет посвящен другой теме и наверняка пригодится тем, кто задумывался о необходимости включения в программу вызовов ptr fun, inem fun и mem fun ref. При желании начните с совета 41, но пожалуйста, не останавливайтесь на этом. Когда вы поймете, для чего нужны эти функции, материал остальных советов поможет вам наладить правильное взаимодействие ваших функторов с ними и с STL в целом.

Совет 38. Проектируйте классы функторов для передачи по значению

Ни С, ни C-I-+ не позволяют передавать функции в качестве параметров других функций. Вместо этого разрешается передавать указатели на функции. Например, объявление стандартной библиотечной функции qsort выглядит следующим образом:

void qsortCvoid *base, size t nmemb. size t size.

int (*cmpfcn)(const void*,const void*));

В совете 46 объясняется, почему вместо функции qsort обычно рекомендуется использовать алгоритм sort, но дело не в этом. Нас сейчас интересует объявление



параметра cmpfcn функции qsort. При внимательном анализе становится ясно, что аргумент cmpcfn, который является указателем на функцию, копируется (то есть передается по значению) из точки вызова в функцию qsort. Данный пример поясняет правило, соблюдаемое стандартными библиотеками С и С++, - указатели на функции должны передаваться по значению.

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

template<class Inputlterator.

class Function> Function Возврат по значению

for each(Inputlterator first.

Inputlterator last.

Function f); Передача no значению

Честно говоря, передача по значению не гарантирована полностью, поскольку вызывающая сторона может явно задать типы параметров в точке вызова. Например, в следующем фрагменте foreach получает и возвращает функторы по ссылке:

class DoSomething: public unary function<int,void>{ Базовый класс описан

void operatorO (int x){...} в совете 40

typedef deque<int>::iterator DequeintIter: Вспомогательное определение . deque<i nt> di:

DoSomething d: Создать объект функции

for each<DequeIntIter, Вызвать for each с типами

DoSoniething&>(di .beginO. параметров Dequelntlter

di.endO, и DoSomething&: в результате

d): происходит передача

и возврат по ссылке.

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

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



1 ... 43 44 45 [ 46 ] 47 48 49 ... 71

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