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

Sometimes you need the behavior or efficiency of one kind of container for one part of your program, and you need a different container’s behavior or efficiency in another part of the program. For example, you may need the efficiency of a deque when adding objects to the container but the efficiency of a vector when indexing them. Each of the basic sequence containers (vector, deque, and list) has a two-iterator constructor (indicating the beginning and ending of the sequence to read from when creating a new object) and an assign( ) member function to read into an existing container, so you can easily move objects from one sequence container to another.

The following example reads objects into a deque and then converts to a vector:

//: C07:DequeConversion.cpp

// Reading into a Deque, converting to a vector

//{-bor}

#include

#include

#include

#include

#include

#include "Noisy.h"

using namespace std;

int main(int argc, char* argv[]) {

  int size = 25;

  if(argc >= 2) size = atoi(argv[1]);

  deque d;

  generate_n(back_inserter(d), size, NoisyGen());

  cout << "\n Converting to a vector(1)" << endl;

  vector v1(d.begin(), d.end());

  cout << "\n Converting to a vector(2)" << endl;

  vector v2;

  v2.reserve(d.size());

  v2.assign(d.begin(), d.end());

  cout << "\n Cleanup" << endl;

} ///:~

You can try various sizes, but note that it makes no difference—the objects are simply copy-constructed into the new vectors. What’s interesting is that v1 does not cause multiple allocations while building the vector, no matter how many elements you use. You might initially think that you must follow the process used for v2 and preallocate the storage to prevent messy reallocations, but this is unnecessary because the constructor used for v1 determines the memory need ahead of time.

<p>Cost of overflowing allocated storage</p>

It’s illuminating to see what happens with a deque when it overflows a block of storage, in contrast with VectorOverflow.cpp:

//: C07:DequeOverflow.cpp

//{-bor}

// A deque is much more efficient than a vector

// when pushing back a lot of elements, since it

// doesn't require copying and destroying.

#include

#include

#include "Noisy.h"

using namespace std;

int main(int argc, char* argv[]) {

  int size = 1000;

  if(argc >= 2) size = atoi(argv[1]);

  deque dn;

  Noisy n;

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

    dn.push_back(n);

  cout << "\n cleaning up \n";

} ///:~

Here you will have relatively few (if any) destructors called before the words "cleaning up" appear. Since the deque allocates all its storage in blocks instead of a contiguous array like vector, it never needs to move existing storage of each of its data blocks. (Thus, no additional copy-constructions and destructions occur.) The deque simply allocates a new block. For the same reason, the deque can just as efficiently add elements to the beginning of the sequence, since if it runs out of storage, it (again) just allocates a new block for the beginning. (The index block that holds the data blocks together may need to be reallocated, however.) Insertions in the middle of a deque, however, could be even messier than for vector (but not as costly).

Because of deque’s clever storage management, an existing iterator is not invalidated after you add new things to either end of a deque, as it was demonstrated to do with vector (in VectorCoreDump.cpp). If you stick to what deque is best at—insertions and removals from either end, reasonably rapid traversals and fairly fast random-access using operator[ ]—you’ll be in good shape.

<p>Checked random-access</p>

Both vector and deque provide two ways to perform random access of their elements: the operator[ ], which you’ve seen already, and at( ), which checks the boundaries of the container that’s being indexed and throws an exception if you go out of bounds. It does cost more to use at( ):

//: C07:IndexingVsAt.cpp

// Comparing "at()" to operator[]

#include

#include

#include

#include

#include "../require.h"

using namespace std;

int main(int argc, char* argv[]) {

  long count = 1000;

  int sz = 1000;

  if(argc >= 2) count = atoi(argv[1]);

  if(argc >= 3) sz = atoi(argv[2]);

  vector vi(sz);

  clock_t ticks = clock();

  for(int i1 = 0; i1 < count; i1++)

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

      vi[j];

  cout << "vector[] " << clock() - ticks << endl;

  ticks = clock();

  for(int i2 = 0; i2 < count; i2++)

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

      vi.at(j);

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

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

3ds Max 2008
3ds Max 2008

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

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

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