Ray's playground

 

STL Containers & Iterators part2(Chapter 4 of Thinking in C++ Vol 2)

The vector is intentionally made to look like a souped-up array, since it has array-style indexing but also can expand dynamically. vector is so fundamentally useful that it was introduced in a very primitive way early in this book, and used quite regularly in previous examples. This section will give a more in-depth look at vector.
To achieve maximally-fast indexing and iteration, the vector maintains its storage as a single contiguous array of objects. This is a critical point to observe in understanding the behavior of vector. It means that indexing and iteration are lighting-fast, being basically the same as indexing and iterating over an array of objects. But it also means that inserting an object anywhere but at the end (that is, appending) is not really an acceptable operation for a vector. It also means that when a vector runs out of pre-allocated storage, in order to maintain its contiguous array it must allocate a whole new (larger) chunk of storage elsewhere and copy the objects to the new storage. This has a number of unpleasant side effects.
The deque (double-ended-queue, pronounced “deck”) is the basic sequence container optimized for adding and removing elements from either end. It also allows for reasonably fast random access – it has an operator[ ] like vector. However, it does not have vector’s constraint of keeping everything in a single sequential block of memory. Instead, deque uses multiple blocks of sequential storage (keeping track of all the blocks and their order in a mapping structure). For this reason the overhead for a deque to add or remove elements at either end is very low. In addition, it never needs to copy and destroy contained objects during a new storage allocation (like vector does) so it is far more efficient than vector if you are adding an unknown quantity of objects. This means that vector is the best choice only if you
have a pretty good idea of how many objects you need. In addition, many of the programs shown earlier in this book that use vector and push_back( ) might be more efficient with a deque. The interface to deque is only slightly different from a vector (deque has a push_front( ) and pop_front( ) while vector does not, for example) so converting code from using vector to using deque is almost trivial. 
A list is implemented as a doubly-linked list and is thus designed for rapid insertion and removal of elements in the middle of the sequence (whereas for vector and deque this is a much more costly operation). A list is so slow when randomly accessing elements that it does not have an operator[ ]. It’s best used when you’re traversing a sequence, in order, from beginning to end (or end to beginning) rather than choosing elements randomly from the middle. Even then the traversal is significantly slower than either a vector or a deque, but if
you aren’t doing a lot of traversals that won’t be your bottleneck.
Another thing to be aware of with a list is the memory overhead of each link, which requires a forward and backward pointer on top of the storage for the actual object. Thus a list is a better choice when you have larger objects that you’ll be inserting and removing from the middle of the list. It’s better not to use a list if you think you might be traversing it a lot, looking for objects, since the amount of time it takes to get from the beginning of the list – which is the only place you can start unless you’ve already got an iterator to somewhere you know is closer to your destination – to the object of interest is proportional to the number of objects between the beginning and that object.
The objects in a list never move after they are created; “moving” a list element means changing the links, but never copying or assigning the actual objects. This means that a held iterator never moves when you add new things to a list as it was demonstrated to do in vector. 
Performance
  1 #include <vector>
  2 #include <queue>
  3 #include <list>
  4 #include <iostream>
  5 #include <string>
  6 #include <typeinfo>
  7 #include <ctime>
  8 #include <cstdlib>
  9 using namespace std;
 10 
 11 class FixedSize 
 12 {
 13     int x[20];
 14     // Automatic generation of default constructor,
 15     // copy-constructor and operator=
 16 } fs;
 17 
 18 template<class Cont>
 19 struct InsertBack 
 20 {
 21     void operator()(Cont& c, long count) 
 22     {
 23         for(long i = 0; i < count; i++)
 24             c.push_back(fs);    
 25     }
 26 
 27     char* testName() { return "InsertBack"; }
 28 };
 29 
 30 template<class Cont>
 31 struct InsertFront 
 32 {
 33     void operator()(Cont& c, long count) 
 34     {
 35         long cnt = count * 10;
 36         for(long i = 0; i < cnt; i++)
 37             c.push_front(fs);
 38     }
 39 
 40     char* testName() { return "InsertFront"; }
 41 };
 42 
 43 template<class Cont>
 44 struct InsertMiddle 
 45 {
 46     void operator()(Cont& c, long count) 
 47     {
 48         typename Cont::iterator it;
 49         long cnt = count / 10;
 50         for(long i = 0; i < cnt; i++
 51         {
 52             // Must get the iterator every time to keep
 53             // from causing an access violation with
 54             // vector. Increment it to put it in the
 55             // middle of the container:
 56             it = c.begin();
 57             it++;
 58             c.insert(it, fs);
 59         }
 60     }
 61 
 62     char* testName() { return "InsertMiddle"; }
 63 };
 64 
 65 template<class Cont>
 66 struct RandomAccess 
 67 // Not for list
 68     void operator()(Cont& c, long count) 
 69     {
 70         int sz = c.size();
 71         long cnt = count * 100;
 72         for(long i = 0; i < cnt; i++)
 73             c[rand() % sz];
 74     }
 75     char* testName() { return "RandomAccess"; }
 76 };
 77 
 78 template<class Cont>
 79 struct Traversal 
 80 {
 81     void operator()(Cont& c, long count) 
 82     {
 83         long cnt = count / 100;
 84         for(long i = 0; i < cnt; i++
 85         {
 86             typename Cont::iterator it = c.begin(),
 87             end = c.end();
 88             while(it != end) it++;
 89         }
 90     }
 91 
 92     char* testName() { return "Traversal"; }
 93 };
 94 
 95 template<class Cont>
 96 struct Swap 
 97 {
 98     void operator()(Cont& c, long count) 
 99     {
100         int middle = c.size() / 2;
101         typename Cont::iterator it = c.begin(),
102         mid = c.begin();
103         it++// Put it in the middle
104         for(int x = 0; x < middle + 1; x++)
105             mid++;
106         long cnt = count * 10;
107         for(long i = 0; i < cnt; i++)
108             swap(*it, *mid);
109     }
110 
111     char* testName() { return "Swap"; }
112 };
113 
114 template<class Cont>
115 struct RemoveMiddle 
116 {
117     void operator()(Cont& c, long count) 
118     {
119         long cnt = count / 10;
120         if(cnt > c.size()) 
121         {
122             cout << "RemoveMiddle: not enough elements" << endl;
123             return;
124         }
125         for(long i = 0; i < cnt; i++
126         {
127             typename Cont::iterator it = c.begin();
128             it++;
129             c.erase(it);
130         }
131     }
132 
133     char* testName() { return "RemoveMiddle"; }
134 };
135 
136 template<class Cont>
137 struct RemoveBack 
138 {
139     void operator()(Cont& c, long count) 
140     {
141         long cnt = count * 10;
142         if(cnt > c.size()) 
143         {
144             cout << "RemoveBack: not enough elements" << endl;
145             return;
146         }
147         for(long i = 0; i < cnt; i++)
148             c.pop_back();
149     }
150 
151     char* testName() { return "RemoveBack"; }
152 };
153 
154 template<class Op, class Container>
155 void measureTime(Op f, Container& c, long count)
156 {
157     string id(typeid(f).name());
158     bool Deque = id.find("deque"!= string::npos;
159     bool List = id.find("list"!= string::npos;
160     bool Vector = id.find("vector"!=string::npos;
161     string cont = Deque ? "deque" : List ? "list": Vector? "vector" : "unknown";
162     cout << f.testName() << " for " << cont << "";
163     // Standard C library CPU ticks:
164     clock_t ticks = clock();
165     f(c, count); // Run the test
166     ticks = clock() - ticks;
167     cout << ticks << endl;
168 }
169 
170 typedef deque<FixedSize> DF;
171 typedef list<FixedSize> LF;
172 typedef vector<FixedSize> VF;
173 
174 int main(int argc, char* argv[]) 
175 {
176     srand(time(0));
177     long count = 1000;
178     if(argc >= 2
179         count = atoi(argv[1]);
180     DF deq;
181     LF lst;
182     VF vec, vecres;
183     vecres.reserve(count); // Preallocate storage
184     measureTime(InsertBack<VF>(), vec, count);
185     measureTime(InsertBack<VF>(), vecres, count);
186     measureTime(InsertBack<DF>(), deq, count);
187     measureTime(InsertBack<LF>(), lst, count);
188     // Can't push_front() with a vector:
189     //! measureTime(InsertFront<VF>(), vec, count);
190     measureTime(InsertFront<DF>(), deq, count);
191     measureTime(InsertFront<LF>(), lst, count);
192     measureTime(InsertMiddle<VF>(), vec, count);
193     measureTime(InsertMiddle<DF>(), deq, count);
194     measureTime(InsertMiddle<LF>(), lst, count);
195     measureTime(RandomAccess<VF>(), vec, count);
196     measureTime(RandomAccess<DF>(), deq, count);
197     // Can't operator[] with a list:
198     //! measureTime(RandomAccess<LF>(), lst, count);
199     measureTime(Traversal<VF>(), vec, count);
200     measureTime(Traversal<DF>(), deq, count);
201     measureTime(Traversal<LF>(), lst, count);
202     measureTime(Swap<VF>(), vec, count);
203     measureTime(Swap<DF>(), deq, count);
204     measureTime(Swap<LF>(), lst, count);
205     measureTime(RemoveMiddle<VF>(), vec, count);
206     measureTime(RemoveMiddle<DF>(), deq, count);
207     measureTime(RemoveMiddle<LF>(), lst, count);
208     vec.resize(vec.size() * 10); // Make it bigger
209     measureTime(RemoveBack<VF>(), vec, count);
210     measureTime(RemoveBack<DF>(), deq, count);
211     measureTime(RemoveBack<LF>(), lst, count);
212 
213     cin.get();
214 ///:~

 

 

posted on 2011-02-22 17:22  Ray Z  阅读(262)  评论(0编辑  收藏  举报

导航