Читаем Thinking In C++. Volume 2: Practical Programming полностью

The first form of transform( ) simply calls f(*first), where first ranges through the input sequence. Similarly, the second form calls f(*first1, *first2). (Note that the length of the second input range is determined by the length of the first.) The return value in both cases is the past-the-end iterator for the resulting output range.

<p>Examples</p>

Since much of what you do with objects in a container is to apply an operation to all those objects, these are fairly important algorithms and merit several illustrations.

First, consider for_each( ). This sweeps through the range, pulling out each element and passing it as an argument as it calls whatever function object it’s been given. Thus, for_each( ) performs operations that you might normally write out by hand. If you look in your compiler’s header file at the template defining for_each( ), you’ll see something like this:.

template

Function for_each(InputIterator first,

   InputIterator last,

   Function f) {

    while (first != last) f(*first++);

    return f;

}

The following example shows several ways this template can be expanded. First, we need a class that keeps track of its objects so we can know that it’s being properly destroyed:.

//: C06:Counted.h

// An object that keeps track of itself

#ifndef COUNTED_H

#define COUNTED_H

#include

#include

class Counted {

  static int count;

  char* ident;

public:

  Counted(char* id) : ident(id) { count++; }

  ~Counted() {

    std::cout << ident << " count = "

      << --count << std::endl;

  }

};

int Counted::count = 0;

class CountedVector :

  public std::vector {

public:

  CountedVector(char* id) {

    for(int i = 0; i < 5; i++)

      push_back(new Counted(id));

  }

};

#endif // COUNTED_H ///:~

The class Counted keeps a static count of how many Counted objects have been created and tells you as they are destroyed.[89] In addition, each Counted keeps a char* identifier to make tracking the output easier.

The CountedVector is derived from vector, and in the constructor it creates some Counted objects, handing each one your desired char*. The CountedVector makes testing quite simple, as you’ll see.

//: C06:ForEach.cpp

// Use of STL for_each() algorithm

#include

#include

#include "Counted.h"

using namespace std;

// Function object:

template

class DeleteT {

public:

  void operator()(T* x) { delete x; }

};

// Template function:

template

void wipe(T* x) { delete x; }

int main() {

  CountedVector B("two");

  for_each(B.begin(),B.end(),DeleteT());

  CountedVector C("three");

  for_each(C.begin(), C.end(), wipe);

} ///:~

Since this is obviously something you might want to do a lot, why not create an algorithm to delete all the pointers in a container? You could use transform( ). The value of transform( ) over for_each( ) is that transform( ) assigns the result of calling the function object into a resulting range, which can actually be the input range. That case means a literal transformation for the input range, since each element would be a modification of its previous value. In this example, this approach would be especially useful since it’s more appropriate to assign to each pointer the safe value of zero after calling delete for that pointer. Transform( ) can easily do this:.

//: C06:Transform.cpp

// Use of STL transform() algorithm

#include "Counted.h"

#include

#include

#include

using namespace std;

template

T* deleteP(T* x) { delete x; return 0; }

#ifdef _MSC_VER

// Microsoft needs explicit instantiation

template Counted* deleteP(Counted* x);

#endif

template struct Deleter {

  T* operator()(T* x) { delete x; return 0; }

};

int main() {

  CountedVector cv("one");

  transform(cv.begin(), cv.end(), cv.begin(),

    deleteP);

  CountedVector cv2("two");

  transform(cv2.begin(), cv2.end(), cv2.begin(),

    Deleter());

} ///:~

This shows both approaches: using a template function or a templatized function object. After the call to transform( ), the vector contains five null pointers, which is safer since any duplicate deletes will have no effect.

One thing you cannot do is delete every pointer in a collection without wrapping the call to delete inside a function or an object. That is, you do the following:.

for_each(a.begin(), a.end(), ptr_fun(operator delete));

This has the same problem as the call to destroy ( ) did earlier: operator delete( ) takes a void*, but iterators aren’t void pointers (or pointers at all). Even if you could make it compile, what you’d get is a sequence of calls to the function that releases the storage. You will not get the effect of calling delete for each pointer in a, however; the destructor will not be called. This is typically not what you want, so you will need wrap your calls to delete.

Перейти на страницу:

Похожие книги

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных