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

The insertion iterators are necessary because some of the STL algorithms—copy( ), for example—use the assignment operator= to place objects in the destination container. This is a problem when you’re using the algorithm to fill the container rather than to overwrite items that are already in the destination container—that is, when the space isn’t already there. What the insert iterators do is change the implementation of operator= so that instead of doing an assignment, it calls a "push" or "insert" function for that container, thus causing it to allocate new space. The constructors for both back_insert_iterator and front_insert_iterator take a basic sequence container object (vector, deque or list) as their argument and produce an iterator that calls push_back( ) or push_front( ), respectively, to perform assignment. The helper functions back_inserter( ) and front_inserter( ) produce the same objects with a little less typing. Since all the basic sequence containers support push_back( ), you will probably find yourself using back_inserter( ) with some regularity.

An insert_iterator lets you insert elements in the middle of the sequence, again replacing the meaning of operator=, but this time by automatically calling insert( ) instead of one of the "push" functions. The insert( ) member function requires an iterator indicating the place to insert before, so the insert_iterator requires this iterator in addition to the container object. The shorthand function inserter( ) produces the same object.

The following example shows the use of the different types of inserters:

//: C07:Inserters.cpp

// Different types of iterator inserters

#include

#include

#include

#include

#include

using namespace std;

int a[] = { 1, 3, 5, 7, 11, 13, 17, 19, 23 };

template

void frontInsertion(Cont& ci) {

  copy(a, a + sizeof(a)/sizeof(Cont::value_type),

    front_inserter(ci));

  copy(ci.begin(), ci.end(),

    ostream_iterator(

    cout, " "));

  cout << endl;

}

template

void backInsertion(Cont& ci) {

  copy(a, a + sizeof(a)/sizeof(Cont::value_type),

    back_inserter(ci));

  copy(ci.begin(), ci.end(),

    ostream_iterator(

    cout, " "));

  cout << endl;

}

template

void midInsertion(Cont& ci) {

  typename Cont::iterator it = ci.begin();

  it++; it++; it++;

  copy(a, a + sizeof(a)/(sizeof(Cont::value_type) * 2),

    inserter(ci, it));

  copy(ci.begin(), ci.end(),

    ostream_iterator(

    cout, " "));

  cout << endl;

}

int main() {

  deque di;

  list  li;

  vector vi;

  // Can't use a front_inserter() with vector

  frontInsertion(di);

  frontInsertion(li);

  di.clear();

  li.clear();

  backInsertion(vi);

  backInsertion(di);

  backInsertion(li);

  midInsertion(vi);

  midInsertion(di);

  midInsertion(li);

} ///:~

Since vector does not support push_front( ), it cannot produce a front_insertion_iterator. However, you can see that vector does support the other two types of insertions (even though, as you shall see later, insert( ) is not an efficient operation for vector). Note the use of the nested type Cont::value_type instead of hard-coding int.

<p>More on stream iterators</p>

We introduced the use of the stream iterators ostream_iterator (an output iterator) and istream_iterator (an input iterator) in conjunction with copy( ) in the previous chapter. Remember that an output stream doesn’t have any concept of an "end," since you can always just keep writing more elements. However, an input stream eventually terminates (for example, when you reach the end of a file), so you need a way to represent that. An istream_iterator has two constructors, one that takes an istream and produces the iterator you actually read from, and the other which is the default constructor and produces an object that is the past-the-end sentinel. In the following program this object is named end:

//: C07:StreamIt.cpp

// Iterators for istreams and ostreams

#include

#include

#include

#include

#include

#include "../require.h"

using namespace std;

int main() {

  ifstream in("StreamIt.cpp");

  assure(in, "StreamIt.cpp");

  istream_iterator begin(in), end;

  ostream_iterator out(cout, "\n");

  vector vs;

  copy(begin, end, back_inserter(vs));

  copy(vs.begin(), vs.end(), out);

  *out++ = vs[0];

  *out++ = "That's all, folks!";

} ///:~

When in runs out of input (in this case when the end of the file is reached), init becomes equivalent to end, and the copy( ) terminates.

Because out is an ostream_iterator, you can simply assign any string object to the dereferenced iterator using operator=, and that string will be placed on the output stream, as seen in the two assignments to out. Because out is defined with a newline as its second argument, these assignments also insert a newline along with each assignment.

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

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

3ds Max 2008
3ds Max 2008

Одни уверены, что нет лучшего способа обучения 3ds Мах, чем прочитать хорошую книгу. Другие склоняются к тому, что эффективнее учиться у преподавателя, который показывает, что и как нужно делать. Данное издание объединяет оба подхода. Его цель – сделать освоение 3ds Мах 2008 максимально быстрым и результативным. Часто после изучения книги у читателя возникают вопросы, почему не получился тот или иной пример. Видеокурс – это гарантия, что такие вопросы не возникнут: ведь автор не только рассказывает, но и показывает, как нужно работать в 3ds Мах.В отличие от большинства интерактивных курсов, где работа в 3ds Мах иллюстрируется на кубиках-шариках, данный видеокурс полностью практический. Все приемы работы с инструментами 3ds Мах 2008 показаны на конкретных примерах, благодаря чему после просмотра курса читатель сможет самостоятельно выполнять даже сложные проекты.

Владимир Антонович Верстак , Владимир Верстак

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