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

Although it is possible to create an istream_iterator and ostream_iterator, these actually parse the input and thus will, for example, automatically eat whitespace (spaces, tabs, and newlines), which is not desirable if you want to manipulate an exact representation of an istream. Instead, you can use the special iterators istreambuf_iterator and ostreambuf_iterator, which are designed strictly to move characters[94]. Although these are templates, they are meant to be used with template arguments of either char or wchar_t.[95] The following example lets you compare the behavior of the stream iterators with the streambuf iterators:.

//: C07:StreambufIterator.cpp

// istreambuf_iterator & ostreambuf_iterator

#include

#include

#include

#include

#include "../require.h"

using namespace std;

int main() {

  ifstream in("StreambufIterator.cpp");

  assure(in, "StreambufIterator.cpp");

  // Exact representation of stream:

  istreambuf_iterator isb(in), end;

  ostreambuf_iterator osb(cout);

  while(isb != end)

    *osb++ = *isb++; // Copy 'in' to cout

  cout << endl;

  ifstream in2("StreambufIterator.cpp");

  // Strips white space:

  istream_iterator is(in2), end2;

  ostream_iterator os(cout);

  while(is != end2)

    *os++ = *is++;

  cout << endl;

} ///:~

The stream iterators use the parsing defined by istream::operator>>, which is probably not what you want if you are parsing characters directly—it’s fairly rare that you want all the whitespace stripped out of your character stream. You’ll virtually always want to use a streambuf iterator when using characters and streams, rather than a stream iterator. In addition, istream::operator>> adds significant overhead for each operation, so it is only appropriate for higher-level operations such as parsing numbers.[96]

<p>Manipulating raw storage</p>

The raw_storage_iterator is defined in and is an output iterator. It is provided to enable algorithms to store their results in uninitialized memory. The interface is quite simple: the constructor takes an output iterator that is pointing to the raw memory (thus it is typically a pointer), and the operator= assigns an object into that raw memory. The template parameters are the type of the output iterator pointing to the raw storage and the type of object that will be stored. Here’s an example that creates Noisy objects, which print trace statements for their construction, assignment, and destruction (we’ll show the class definition later):

//: C07:RawStorageIterator.cpp

// Demonstrate the raw_storage_iterator

//{-bor}

#include

#include

#include

#include "Noisy.h"

using namespace std;

int main() {

  const int quantity = 10;

  // Create raw storage and cast to desired type:

  Noisy* np =

    reinterpret_cast(

      new char[quantity * sizeof(Noisy)]);

  raw_storage_iterator rsi(np);

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

    *rsi++ = Noisy(); // Place objects in storage

  cout << endl;

  copy(np, np + quantity,

    ostream_iterator(cout, " "));

  cout << endl;

  // Explicit destructor call for cleanup:

  for(int j = 0; j < quantity; j++)

    (&np[j])->~Noisy();

  // Release raw storage:

  delete reinterpret_cast(np);

} ///:~

To make the raw_storage_iterator template happy, the raw storage must be of the same type as the objects you’re creating. That’s why the pointer from the new array of char is cast to a Noisy*. The assignment operator forces the objects into the raw storage using the copy-constructor. Note that the explicit destructor call must be made for proper cleanup, and this also allows the objects to be deleted one at a time during container manipulation. In addition, the expression delete np; would be invalid anyway since the static type of a pointer in a delete expression must be the same as the type assigned to in the new expression.

<p>The basic sequences: vector, list, deque</p>

Sequences keep objects in whatever order you store them. They differ in the efficiency of their operations, however, so if you are going to manipulate a sequence in a particular fashion, choose the appropriate container for those types of manipulations. So far in this book we’ve been using vector as the container of choice. This is quite often the case in applications. However, when you start making more sophisticated uses of containers, it becomes important to know more about their underlying implementations and behavior so that you can make the right choices.

<p>Basic sequence operations</p>

Using a template, the following example shows the operations that all the basic sequences, vector, deque, and list, support.

//: C07:BasicSequenceOperations.cpp

// The operations available for all the

// basic sequence Containers.

#include

#include

#include

#include

using namespace std;

template

void print(Container& c, char* title = "") {

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

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

3ds Max 2008
3ds Max 2008

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

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

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