Although it is possible to create an istream_iterator
//: 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
ostreambuf_iterator
while(isb != end)
*osb++ = *isb++; // Copy 'in' to cout
cout << endl;
ifstream in2("StreambufIterator.cpp");
// Strips white space:
istream_iterator
ostream_iterator
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]
Manipulating raw storage
The raw_storage_iterator is defined in
//: 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
for(int i = 0; i < quantity; i++)
*rsi++ = Noisy(); // Place objects in storage
cout << endl;
copy(np, np + quantity,
ostream_iterator
cout << endl;
// Explicit destructor call for cleanup:
for(int j = 0; j < quantity; j++)
(&np[j])->~Noisy();
// Release raw storage:
delete reinterpret_cast
} ///:~
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.
The basic sequences: vector, list, deque
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.
Basic sequence operations
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 = "") {