标准模板库(STL)介绍(英文版)

Introduction to STL, Standard Template Library

By Scott Field


This article is about a new extension to the C++ language, the Standard Template Library, otherwise known as STL.

When I first proposed the idea of an article on STL, I must say I somewhat underestimated the depth and breadth of the topic. There is a lot of ground to cover and there are a number of books describing STL in detail. So I looked at my original idea and refocussed. Why was I writing an article and what could I contribute? What would be useful? Was there a need for another STL article.

As I turned the pages of Musser and Saini I could see programming time dissolving in front of me. I could see late nights disappearing, and on target software projects reappearing. I could see maintainable code. A year has passed since then and the software I have written using STL has been remarkably easy to maintain. And shock horror, other people can maintain it as well, without me!

However, I also remembered that at the beginning it was difficult wading through the technical jargon. Once I bought Musser & Saini everything fell into place but before that it was a real struggle and the main thing I yearned for was some good examples.

Also the third edition of Stroustrup which covers STL as part of C++ was not out when I started.

So I thought it might be useful to write an article about real life use of STL for new STL programmers. I always learn faster if I can get my hands on some good examples, particularly on new subjects like this.

The other thing is, STL is supposed to be easy to use. So theoretically we should be able to start using STL straight away.

What is STL? STL stands for the Standard Template Library. Possibly one of the most boring terms in history, for one of the most exciting tools in history. STL basically consists of a bunch of containers - lists, vectors, sets, maps and more, and a bunch of algorithms and other components. This "bunch of containers and algorithms" took some of the brightest people in the world many years to create.

The purpose of STL is to standardise commonly used components so you don't have to keep reinventing them. You can just use the standard STL components off the shelf. STL is also part of C++ now, so there will be no more extra bits and pieces to collect and install. It will be built into your compiler. Because the STL list is one of the simpler containers, I thought that it might be a good place to start in demonstrating the practical use of STL. If you understand the concepts behind this one, you'll have no trouble with the rest. Besides, there is an awful lot to a simple list container, as we'll see.

In this article we will see how to define and initialise a list, count elements, find elements in a list, remove elements, and other very useful operations. In doing so we will cover two different kinds of algorithms, STL generic algorithms which work with more than one container, and list member functions which work exclusively with the list container.

Just in case anyone's wondering, here is a brief rundown on the three main kinds of STL components. The STL containers hold objects, built in objects and class objects. They keep the objects secure and define a standard interface through which we can manipulate the objects. Eggs in an egg container won't roll off the kitchen bench. They are safe. So it is with objects in STL containers. They are safe. I know that sounds corny but it's true.

STL algorithms are standard algorithms we can apply to the objects while they are in the container. The algorithms have well known execution characteristics. They can sort the objects, remove them, count them, compare them, find a particular one, merge objects into another container, and carry out many other useful operations.

STL iterators are like pointers to the objects in the containers. STL algorithms use iterators to operate on containers. Iterators set bounds for algorithms, regarding the extent of the container, and in other ways. For example some iterators only let the algorithms read elements, some allow them to write elements, some both. Iterators also determine the direction of processing in a container.

You can obtain iterators to the first position in a container by calling the container member function begin(). You can call the container end() function to get the past the end value (where to stop processing).

This is what STL is all about, containers, algorithms, and iterators to allow the algorithms to work on the elements in the containers. The algorithms manipulate the objects in a measurable, standard way, and are made aware of the precise extent of the container via iterators. Once this is done they won't ever "run off the edge". There are other components which enhance the functionality of these core component types, such as function objects. We will also look at some examples of these. For now, lets take a look at the STL list.


Defining a List

We can define an STL list like this.

 
#include <string>

#include <list>
int main (void) {
list<string> Milkshakes;
}
Thats to it. You've defined a list. Could it have been any easier? By saying list<string> Milkshakes you've instantiated a template class list<string>, and then instantiated an object of that type. But lets not fuss with that. At this stage you really only need to know that you have defined a list of strings. You need the header file list to provide the STL list class. I compiled these test programs using GCC 2.7.2 on my Linux box. For example:
 
g++ test1.cpp -otest1
Note that the include file iostream.h is buried in one of the STL header files. Thats why it is missing in some of the examples.

Now that we have a list, we can start using it to hold things. We'll add some strings to the list. There is an important thing called the value type of the list. The value type is the type of the object the list holds. In this case the value type of the list is string, as the list holds strings.


Inserting elements into a list with the list member functions push_back and push_front
 
#include <string>
#include <list>

int main (void) {
list<string> Milkshakes;
Milkshakes.push_back("Chocolate");
Milkshakes.push_back("Strawberry");
Milkshakes.push_front("Lime");
Milkshakes.push_front("Vanilla");
}

We now have a list with four strings in it. The list member function push_back() places an object onto the back of the list. The list member function push_front() puts one on the front. I often push_back() some error messages onto a list, and then push_front() a title on the list so it prints before the error messages.


The list member function empty()

It is important to know if a list is empty. The empty() list member function returns true if the list is empty. Empty is a deceptively simple concept. I often use it in the following way. Throughout a program I use push_back() to put error messages onto a list. Then by calling empty() I can tell if the program has reported any errors. If I define one list for informational messages, one for warnings, and one for serious errors, I can easily tell what types of errors have occurred just by using empty().

I can populate these lists throughout the program, then smarten them up with a title, or maybe sort them into categories, before printing them out.

Here's what I mean.

 
/*
|| Using a list to track and report program messages and status
*/
#include <iostream.h>

#include <string>
#include <list>

int main (void) {
#define OK 0
#define INFO 1
#define WARNING 2

int return_code;

list<string> InfoMessages;
list&lt:string> WarningMessages;

// during a program these messages are loaded at various points
InfoMessages.push_back("Info: Program started");
// do work...
WarningMessages.push_back("Warning: No Customer records have been found");
// do work...

return_code = OK;

if (!InfoMessages.empty()) { // there were info messages
InfoMessages.push_front("Informational Messages:");
// ... print the info messages list, we'll see how later
return_code = INFO;
}

if (!WarningMessages.empty()) { // there were warning messages
WarningMessages.push_front("Warning Messages:");
// ... print the warning messages list, we'll see how later
return_code = WARNING;
}

// If there were no messages say so.
if (InfoMessages.empty() && WarningMessages.empty()) {
cout << "There were no messages " << endl;
}

return return_code;
}


Processing elements in a list with a for loop

We will want to be able to iterate through any list, to, for example, print all the objects in the list to see the effect of various operations on a list. To iterate through a list, element by element we can proceed as follows

 
/*
|| How to print the contents of a simple STL list. Whew!
*/
#include <iostream.h>
#include <string>
#include <list>

int main (void) {
list<string> Milkshakes;
list<string>::iterator MilkshakeIterator;

Milkshakes.push_back("Chocolate");
Milkshakes.push_back("Strawberry");
Milkshakes.push_front("Lime");
Milkshakes.push_front("Vanilla");

// print the milkshakes
Milkshakes.push_front("The Milkshake Menu");
Milkshakes.push_back("*** Thats the end ***");
for (MilkshakeIterator=Milkshakes.begin();
MilkshakeIterator!=Milkshakes.end();
++MilkshakeIterator) {
// dereference the iterator to get the element
cout << *MilkshakeIterator << endl;
}
}
In this program we define an iterator, MilkshakeIterator. We set MilkshakeIterator to the first element of the list. To do this we call Milkshakes.begin() which returns an iterator to the beginning of the list. We then compare MilkshakeIterator to the end of list value Milkshakes.end(), and stop when we get there.

The end() function of a container returns an iterator to the position one past the end of the container. When we get there, we stop processing. We cannot dereference the iterator returned by a container's end() function. We just know it means we have passed the end of the container and should stop processing elements. This holds for all STL containers.

In the above example at each pass through the for loop we dereference the iterator to obtain the string, which we print.

In STL programming we use one or more iterators in every algorithm. We use them to access objects in a container. To access a given object we point the iterator at the required object, then we dereference the iterator.

The list container, in case you're wondering, does not support adding a number to a list iterator to jump to another object in the container. That is, we cannot say Milkshakes.begin()+2 to point to the third object in the list, because the STL list is implemented as a double linked list, which does not support random access. The vector and deque containers, other STL containers, do provide random access.

The above program printed the contents of the list. Anyone reading it can immediately see how it works. It uses standard iterators and a standard list container. There is not much programmer dependent stuff in it, or a home grown list implementation. Just standard C++. That's an important step forward. Even this simple use of STL makes our software more standard.


Processing elements in a list with the STL generic algorithm for_each

Even with an STL list and iterator we are still initialising, testing, and incrementing the iterator to iterate through a container. The STL generic for_each algorithm can relieve us of that work.

 
/*
|| How to print a simple STL list MkII
*/
#include <iostream.h>

#include <string>
#include <list>
#include <algorithm>

PrintIt (string& StringToPrint) {
cout << StringToPrint << endl;
}

int main (void) {
list<string> FruitAndVegetables;
FruitAndVegetables.push_back("carrot");
FruitAndVegetables.push_back("pumpkin");
FruitAndVegetables.push_back("potato");
FruitAndVegetables.push_front("apple");
FruitAndVegetables.push_front("pineapple");

for_each (FruitAndVegetables.begin(), FruitAndVegetables.end(), PrintIt);
}

In this program we use the STL generic algorithm for_each() to iterate though an iterator range and invoke the function PrintIt() on each object. We don't need to initialise, test or increment any iterators. for_each() nicely modularises our code. The operation we are performing on the object is nicely packaged away in a function, we have gotten rid of the loop, and our code is clearer.

The for_each algorithm introduces the concept of an iterator range, specified by a start iterator and an end iterator. The start iterator specifies where to start processing and the end iterator signifies where to stop processing, but is not included in the range.


Counting elements in a list with the STL generic algorithm count()

The STL generic algorithms count() and count_if() count occurrences of objects in a container. Like for_each(), the count() and count_if() algorithms take an iterator range.

Lets count the number of best possible scores in a list of student's exam scores, a list of ints.

 
/*
|| How to count objects in an STL list
*/
#include <list>

#include <algorithm>

int main (void) {
list<int> Scores;

Scores.push_back(100); Scores.push_back(80);
Scores.push_back(45); Scores.push_back(75);
Scores.push_back(99); Scores.push_back(100);

int NumberOf100Scores(0);
count (Scores.begin(), Scores.end(), 100, NumberOf100Scores);

cout << "There were " << NumberOf100Scores << " scores of 100" << endl;
}
The count() algorithm counts the number of objects equal to a certain value. In the above example it checks each integer object in a list against 100. It increments the variable NumberOf100Scores each time a container object equals 100. The output of the program is
 
There were 2 scores of 100


Counting elements in a list with the STL generic algorithm count_if()

count_if() is a much more interesting version of count(). It introduces a new STL component, the function object. count_if() takes a function object as a parameter. A function object is a class with at least operator () defined. Some STL algorithms accept function objects as parameters and invoke operator () of the function object for each container object being processed.

Function objects intended for use with STL algorithms have their function call operator returning true or false. They are called predicate function objects for this reason. An example will make this clear. count_if() uses the passed in function object to make a more complex assessment than count() of whether an object should be counted. In this example we will count toothbrushes sold. We will refer to sales records containing a four character product code and a description of the product.

 
/*
|| Using a function object to help count things
*/
#include <string>

#include <list>
#include <algorithm>

const string ToothbrushCode("0003");

class IsAToothbrush {
public:
bool operator() ( string& SalesRecord ) {
return SalesRecord.substr(0,4)==ToothbrushCode;
}
};

int main (void) {
list<string> SalesRecords;

SalesRecords.push_back("0001 Soap");
SalesRecords.push_back("0002 Shampoo");
SalesRecords.push_back("0003 Toothbrush");
SalesRecords.push_back("0004 Toothpaste");
SalesRecords.push_back("0003 Toothbrush");

int NumberOfToothbrushes(0);
count_if (SalesRecords.begin(), SalesRecords.end(),
IsAToothbrush(), NumberOfToothbrushes);

cout << "There were "
<< NumberOfToothbrushes
<< " toothbrushes sold" << endl;
}

The output of the program is
 
There were 2 toothbrushes sold
The program works as follows: A function object class is defined, IsAToothbrush. Objects of this class can determine whether a sales record is a toothbrush sales record or not. Their function call operator () will return true if a record is a toothbrush sales record and false otherwise.

The count_if() algorithm will process container objects in the range specified by the first and second iterator parameters. It will increment NumberOfToothbrushes for each object in the container for which IsAToothbrush()() returns true.

The net result is that NumberOfToothbrushes will contain the number of sales records where the product code was "0003", that is, where the product was a toothbrush.

Note that the third parameter to count_if(), IsAToothbrush(), is a temporary object constructed with it's default constructor. The () do not signify a function call. You are passing a temporary object of class IsAToothbrush to count_if(). count_if() will internally invoke IsAToothbrush()() for each object in the container.


A more complex function object with the STL generic algorithm count_if()

We can further develop the idea of the function object. Assume we need to pass more information to a function object. We cannot do this using the function call operator, because that must be defined to take only an object of the value type of the list. However by specifying a non-default constructor for IsAToothbrush we can initialise it with whatever information we need. We might need to have a variable code for a toothbrush for example. We can add this extra information into the function object as follows:

 
/*
|| Using a more complex function object
*/
#include <iostream.h>
#include <string>
#include <list>
#include <algorithm>

class IsAToothbrush {
public:
IsAToothbrush(string& InToothbrushCode) :
ToothbrushCode(InToothbrushCode) {}
bool operator() (string& SalesRecord) {
return SalesRecord.substr(0,4)==ToothbrushCode;
}
private:
string ToothbrushCode;
};

int main (void) {
list<string> SalesRecords;

SalesRecords.push_back("0001 Soap");
SalesRecords.push_back("0002 Shampoo");
SalesRecords.push_back("0003 Toothbrush");
SalesRecords.push_back("0004 Toothpaste");
SalesRecords.push_back("0003 Toothbrush");

string VariableToothbrushCode("0003");

int NumberOfToothbrushes(0);
count_if (SalesRecords.begin(), SalesRecords.end(),
IsAToothbrush(VariableToothbrushCode),
NumberOfToothbrushes);
cout << "There were "
<< NumberOfToothbrushes
<< " toothbrushes matching code "
<< VariableToothbrushCode
<< " sold"
<< endl;
}

The output of the program is
 
There were 2 toothbrushes matching code 0003 sold
This example shows how to pass information to the function object. You can define any constructors that you like and you can do any processing in the function object that you like, well, that the compiler will tolerate anyhow.

You can see that function objects really extend the basic counting algorithm.

At this stage we have covered

  • defining a list
  • adding elements to a list
  • how to tell if a list is empty
  • how to iterate through a list using a for loop
  • how to iterate through a list using the STL generic algorithm for_each
  • the begin() and end() list member functions and their meaning
  • the concept of iterator ranges and the fact that the last position of a range is not processed
  • how to count objects in a list using the STL generic algorithms count() and count_if()
  • how to define function objects

These examples were chosen to show commonly needed list operations. If you understand these basic principles you will have no trouble using STL productively. Mind you it does take some practice. We'll now extend our knowledge with some more complicated operations, both list member functions and STL generic algorithms.


Finding objects in a list using the STL generic algorithm find()

How do we find something in a list? The STL generic algorithms find() and find_if() will do that. Like for_each(), count(), and count_if(), these algorithms take an iterator range, specifying what part of a list or any other container for that matter, to process. As usual the first iterator specifies where to start processing, the second iterator specifies where to stop processing. The position specified by the second iterator is not included in processing.

Here's how find() works.

 
/*
|| How to find things in an STL list
*/
#include <string>
#include <list>
#include <algorithm>

int main (void) {
list<string> Fruit;
list<string>::iterator FruitIterator;

Fruit.push_back("Apple");
Fruit.push_back("Pineapple");
Fruit.push_back("Star Apple");

FruitIterator = find (Fruit.begin(), Fruit.end(), "Pineapple");

if (FruitIterator == Fruit.end()) {
cout << "Fruit not found in list" << endl;
}
else {
cout << *FruitIterator << endl;
}
}
The output of the program will be
 

Pineapple
If find does not find the specified object, it returns the past the end iterator Fruit.end(). Otherwise it returns an iterator to the found list object.


Finding objects in a list using the STL generic algorithm find_if()

There is another more powerful version of find(). This example demonstrates find_if(), which accepts a function object as a parameter, and uses it to make a more complex assessment of whether an object is "found".

Say we have records containing events and dates stored in chronological order in a list. We wish to find the first event that took place in 1997.

 
/*
|| How to find things in an STL list MkII
*/
#include <string>
#include <list>

#include <algorithm>

class EventIsIn1997 {
public:
bool operator () (string& EventRecord) {
// year field is at position 12 for 4 characters in EventRecord
return EventRecord.substr(12,4)=="1997";
}
};

int main (void) {
list<string> Events;

// string positions 0123456789012345678901234567890123456789012345
Events.push_back("07 January 1995 Draft plan of house prepared");
Events.push_back("07 February 1996 Detailed plan of house prepared");
Events.push_back("10 January 1997 Client agrees to job");
Events.push_back("15 January 1997 Builder starts work on bedroom");
Events.push_back("30 April 1997 Builder finishes work");

list<string>::iterator EventIterator =
find_if (Events.begin(), Events.end(), EventIsIn1997());

// find_if completes the first time EventIsIn1997()() returns true
// for any object. It returns an iterator to that object which we
// can dereference to get the object, or if EventIsIn1997()() never
// returned true, find_if returns end()
if (EventIterator==Events.end()) {
cout << "Event not found in list" << endl;
}
else {
cout << *EventIterator << endl;
}
}

The output of the program will be
 
10 January 1997 Client agrees to job


Finding sequences in a list using the STL generic algorithm search

Some characters are a little easier to deal with in an STL container. Lets look at a sequence of characters that can be difficult to work with. We'll define an STL list to hold the characters.

 
list<char> Characters;

We now have a rock solid sequence of characters that knows how to manage it's own memory without any help. It knows precisely where it starts and ends. That's a useful thing. I don't know if I'd say that about a null terminated array of characters.

Lets add some of our favourite characters to the list.

 
Characters.push_back('/0');
Characters.push_back('/0');
Characters.push_back('1');
Characters.push_back('2');
How many null characters have we got?
 
int NumberOfNullCharacters(0);
count(Characters.begin(), Characters.end(), '/0', NumberOfNullCharacters);
cout << "We have " << NumberOfNullCharacters << endl;
Let's find the character '1'
 
list<char>::iterator Iter;
Iter = find(Characters.begin(), Characters.end(), '1');
cout << "We found " << *Iter << endl;
This example is intended to show that STL containers allow you to handle null characters in a more standard way. Now lets search a container for two nulls with the STL search algorithm.

The STL generic algorithm search() searches a container, as you may have guessed, but for a sequence of elements, unlike find() and find_if() which search for a single element.

 
/*
|| How to use the search algorithm in an STL list
*/
#include <string>

#include <list>
#include <algorithm>

int main ( void ) {

list<char> TargetCharacters;
list<char> ListOfCharacters;

TargetCharacters.push_back('/0');
TargetCharacters.push_back('/0');

ListOfCharacters.push_back('1');
ListOfCharacters.push_back('2');
ListOfCharacters.push_back('/0');
ListOfCharacters.push_back('/0');

list<char>::iterator PositionOfNulls =
search(ListOfCharacters.begin(), ListOfCharacters.end(),
TargetCharacters.begin(), TargetCharacters.end());

if (PositionOfNulls!=ListOfCharacters.end())
cout << "We found the nulls" << endl;
}

The output of the program will be
 
We found the nulls
The search algorithm finds the first occurrence of one sequence in another sequence. In this case we search for the first occurrence of TargetCharacters which is a list containing two null characters, in ListOfCharacters.

The parameters for search are two iterators specifying a range to search, and two more iterators specifying a range to search for. So we are looking for the entire range of the TargetCharacters list, in the entire range of ListOfCharacters.

If TargetCharacters is found, search will return an iterator to the first character in ListOfCharacters where the sequences matched. If a match is not found, search will return the past the end value ListOfCharacters.end().


Sorting a list using the list member function sort()

To sort a list we use the list member function sort(), not the generic algorithm sort(). All the algorithms we have been using up till now have been generic algorithms. However in STL, sometimes a container will supply it's own implementation of a particular algorithm, either through necessity or for enhanced performance.

In this case the list container has it's own sort because the generic sort algorithm only sorts containers which provide random access to the elements inside. The list container does not provide random access to the elements in the list, because it is implemented as a linked list. A special sort() member function is needed which can sort a linked list.

You'll find this with STL. For various reasons the containers will supply extra functions, where necessary for efficiency or where special performance gains can be made by taking advantage of some special feature of a container's structure.

 
/*
|| How to sort an STL list
*/
#include <string>
#include <list>
#include <algorithm>

PrintIt (string& StringToPrint) { cout << StringToPrint << endl;}

int main (void) {
list<string> Staff;
list<string>::iterator PeopleIterator;

Staff.push_back("John");
Staff.push_back("Bill");
Staff.push_back("Tony");
Staff.push_back("Fidel");
Staff.push_back("Nelson");

cout << "The unsorted list " << endl;
for_each(Staff.begin(), Staff.end(), PrintIt );

Staff.sort();

cout << "The sorted list " << endl;
for_each(Staff.begin(), Staff.end(), PrintIt);
}

The output is
 
The unsorted list
John
Bill
Tony
Fidel
Nelson
The sorted list
Bill
Fidel
John
Nelson
Tony


Inserting elements in a list with the insert() list member function

The list member functions push_front() and push_back() add elements to the front and back of a list respectively. You can also add an object at any point in a list with insert().

insert() can add one object, a number of copies of an object, or a range of objects. Here are some examples of inserting objects into a list.

 
/*
|| Using insert to insert elements into a list.
*/
#include <list>

int main (void) {
list<int> list1;

/*
|| Put integers 0 to 9 in the list
*/
for (int i = 0; i < 10; ++i) list1.push_back(i);

/*
|| Insert -1 using the insert member function
|| Our list will contain -1,0,1,2,3,4,5,6,7,8,9
*/
list1.insert(list1.begin(), -1);

/*
|| Insert an element at the end using insert
|| Our list will contain -1,0,1,2,3,4,5,6,7,8,9,10
*/
list1.insert(list1.end(), 10);

/*
|| Inserting a range from another container
|| Our list will contain -1,0,1,2,3,4,5,6,7,8,9,10,11,12
*/
int IntArray[2] = {11,12};
list1.insert(list1.end(), &IntArray[0], &IntArray[2]);

/*
|| As an exercise put the code in here to print the lists!
|| Hint: use PrintIt and accept an interger
*/
}
Note that the insert() function adds one or more elements at the position of the iterator you specify. Your elements will appear in the list before the element that was at the specified iterator position.


List constructors

We have been defining a list like this.

 
list<int> Fred;
You can also define a list and initialise it's elements like this
 
// define a list of 10 elements and initialise them all to 0
list<int> Fred(10, 0);
// list now contains 0,0,0,0,0,0,0,0,0,0
Or you can define a list and initialise it with a range from another STL container, which doesn't have to be a list, just a container with the same value type.
 
vector<int> Harry;
Harry.push_back(1);
Harry.push_back(2);

// define a list and initialise it with the elements in Harry
list<int> Bill(Harry.begin(), Harry.end());
// Bill now contains 1,2


Erasing elements from a list using list member functions

The list member function pop_front() removes the first element from a list. pop_back() removes the last element. The member function erase() erases the element pointed to by an iterator. There is another erase() function which can erase a range of elements.

 
/*
|| Erasing objects from a list
*/
#include <list>

int main (void) {
list<int> list1; // define a list of integers

/*
|| Put some numbers in the list
|| It now contains 0,1,2,3,4,5,6,7,8,9
*/
for (int i = 0; i < 10; ++i) list1.push_back(i);

list1.pop_front(); // erase the first element 0

list1.pop_back(); // erase the last element 9

list1.erase(list1.begin()); // erase the first element (1) using an iterator

list1.erase(list1.begin(), list1.end()); // erase all the remaining elements

cout << "list contains " << list1.size() << " elements" << endl;
}

The output will be
 
list contains 0 elements


Removing elements from a list using the list member function remove()

The list member function remove() erases objects from a list.

 
/*
|| Using the list member function remove to remove elements
*/
#include <string>
#include <list>

#include <algorithm>

PrintIt (const string& StringToPrint) {
cout << StringToPrint << endl;
}

int main (void) {
list<string> Birds;

Birds.push_back("cockatoo");
Birds.push_back("galah");
Birds.push_back("cockatoo");
Birds.push_back("rosella");
Birds.push_back("corella");

cout << "Original list with cockatoos" << endl;
for_each(Birds.begin(), Birds.end(), PrintIt);

Birds.remove("cockatoo");

cout << "Now no cockatoos" << endl;
for_each(Birds.begin(), Birds.end(), PrintIt);

}

The output will be
 
Original list with cockatoos
cockatoo
galah
cockatoo
rosella
corella
Now no cockatoos
galah
rosella
corella


Removing elements from a list with the STL generic algorithm remove()

The generic algorithm remove() works in a different way to the list member function remove(). The generic version does not change the size of the container.

 
/*
|| Using the generic remove algorithm to remove list elements
*/
#include <string>
#include <list>

#include <algorithm>

PrintIt(string& AString) { cout << AString << endl; }

int main (void) {
list<string> Birds;
list<string>::iterator NewEnd;

Birds.push_back("cockatoo");
Birds.push_back("galah");
Birds.push_back("cockatoo");
Birds.push_back("rosella");
Birds.push_back("king parrot");

cout << "Original list" << endl;
for_each(Birds.begin(), Birds.end(), PrintIt);

NewEnd = remove(Birds.begin(), Birds.end(), "cockatoo");

cout << endl << "List according to new past the end iterator" << endl;
for_each(Birds.begin(), NewEnd, PrintIt);

cout << endl << "Original list now. Care required!" << endl;
for_each(Birds.begin(), Birds.end(), PrintIt);
}

The output will be
Original list
cockatoo
galah
cockatoo
rosella
king parrot


List according to new past the end iterator
galah
rosella
king parrot


Original list now. Care required!
galah
rosella
king parrot
rosella
king parrot
The generic remove() algorithm returns an iterator specifying a new end to the list. The range from the beginning to the new end (not including the new end) contains the elements left after the remove. You can then erase the range from the new end to the old end using the list member function erase.


Partitioning a list with the STL generic algorithm stable_partition() and using the list member function splice()

We will finish off with a slightly more complicated example. It demonstrates the STL generic stable_partition() algorithm and one variation of the list member function splice(). Notice the use of function objects, and the absence of loops. Control passes through a series of simple statements, which are calls to STL algorithms.

stable_partition() is an interesting function. It rearranges elements so that those which satify a certain condition come before those which do not. It preserves the relative order of the two groups of elements. An example will make this clear.

Splice splices the elements of another list into the list. It removes the elements from the source list.

In this example we want to accept some flags and four filenames from the command line. The filenames must appear in order. By using stable_partition() we can accept the flags at any position relative to the filenames and get them together without disturbing the order of the filename parameters.

Due to the readily available counting and finding algorithms we can call these algorithms as necessary to determine which flag was set rather than setting other flags in our program. I find containers are very convenient for managing small amounts of variable dynamic data like this.

 
/*
|| Using the STL stable_partition algorithm
|| Takes any number of flags on the command line and
|| four filenames in order.
*/
#include <string>
#include <list>
#include <algorithm>

PrintIt ( string& AString ) { cout << AString << endl; }

class IsAFlag {
public:
bool operator () (string& PossibleFlag) {
return PossibleFlag.substr(0,1)=="-";
}
};

class IsAFileName {
public:
bool operator () (string& StringToCheck) {
return !IsAFlag()(StringToCheck);
}
};

class IsHelpFlag {
public:
bool operator () (string& PossibleHelpFlag) {
return PossibleHelpFlag=="-h";
}
};

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

list<string> CmdLineParameters; // the command line parameters
list<string>::iterator StartOfFiles; // start of filenames
list<string> Flags; // list of flags
list<string> FileNames; // list of filenames

for (int i = 0; i < argc; ++i) CmdLineParameters.push_back(argv[i]);

CmdLineParameters.pop_front(); // we don't want the program name

// make sure we have the four mandatory file names
int NumberOfFiles(0);
count_if(CmdLineParameters.begin(), CmdLineParameters.end(),
IsAFileName(), NumberOfFiles);

cout << "The "
<< (NumberOfFiles == 4 ? "correct " : "wrong ")
<< "number ("
<< NumberOfFiles
<< ") of file names were specified" << endl;

// move any flags to the beginning
StartOfFiles =
stable_partition(CmdLineParameters.begin(), CmdLineParameters.end(),
IsAFlag());

cout << "Command line parameters after stable partition" << endl;
for_each(CmdLineParameters.begin(), CmdLineParameters.end(), PrintIt);

// Splice any flags from the original CmdLineParameters list into Flags list.
Flags.splice(Flags.begin(), CmdLineParameters,
CmdLineParameters.begin(), StartOfFiles);

if (!Flags.empty()) {
cout << "Flags specified were:" << endl;
for_each(Flags.begin(), Flags.end(), PrintIt);
}
else {
cout << "No flags were specified" << endl;
}

// parameters list now contains only filenames. Splice them into FileNames list.
FileNames.splice(FileNames.begin(), CmdLineParameters,
CmdLineParameters.begin(), CmdLineParameters.end());

if (!FileNames.empty()) {
cout << "Files specified (in order) were:" << endl;
for_each(FileNames.begin(), FileNames.end(), PrintIt);
}
else {
cout << "No files were specified" << endl;
}

// check if the help flag was specified
if (find_if(Flags.begin(), Flags.end(), IsHelpFlag())!=Flags.end()) {
cout << "The help flag was specified" << endl;
}

// open the files and do whatever you do

}

Given this command line:
 
test17 -w linux -o is -w great
the output is
 
The wrong number (3) of file names were specified
Command line parameters after stable partition
-w
-o
-w
linux
is
great
Flags specified were:
-w
-o
-w
Files specified (in order) were:
linux
is
great


Conclusion

We have only touched on the things you can do with a list. We haven't even got to the point of storing a user defined class of object, although thats not hard.

If you understand the concepts behind the algorithms presented here you should have no trouble using the rest. The important thing with STL is to get the basics right.

The key to STL is really the iterator. STL algorithms take iterators as parameters. They take iterator ranges, sometimes one range, sometimes two. STL containers provide the iterators. Thats why we say list<int>::iterator, or list<char>::iterator, or list<string>::iterator.

Iterators have a well defined heirarchy. They have varying "powers". Some iterators provide read only access to a container, some write only. Some can only iterate forwards, some are bidirectional. Some iterators provide random access to a container.

STL algorithms require a certain "power" of iterator. If the container doesnt provide an iterator of that power, the algorithm will not compile. For example, the list container only provides bidirectional iterators. The generic sort() algorithm requires random access iterators. Thats why we need the special list member function sort().

To really use STL properly you will need to carefully study the various kinds of iterators. You need to see just what kinds of iterators are provided by what containers. You then need to see what type of iterators the algorithms require. You need, of course to understand what kinds of iterators you can have.


Using STL in the field

During the past year I have written a number of commercial C++ programs using STL. It reduced my effort and almost eliminated logic errors in all cases.

The largest program is about 5000 lines. Probably the most striking thing about it is its speed. It reads and extensively processes a 1-2 Mb transaction file in about twenty seconds. It was developed with GCC 2.7.2 on Linux and now runs on a HP-UX machine. It uses over 50 function objects and many containers ranging in size from small lists to a map with over 14,000 elements.

The function objects in the program are in a hierarchy where top level function objects call lower level ones. I used the STL algorithms for_each(), find(), find_if(), count() and count_if() extensively. I reduced nearly all of the internals of the program to STL algorithm calls.

STL tended to automatically organise my code into distinct control and support sections. By carefully crafting function objects and giving them meaningful names I managed to move them out of sight and concentrate on the flow of control in my software.

There is much more to know about STL programming and I hope you have enjoyed working through these examples.

The two books in the bibliography both have active errata pages on the web so you can keep them right up to date.

Stroustrup has an advice section at the back of each chapter which is excellent, especially for beginners and the whole book is in a much more conversational style than the earlier editions. It is also much larger. There are of course quite a few other books on STL in the bookshops. Have a look and see what you can find.

Bibliography
The STL Tutorial and Reference Guide, David Musser and Atul Saini. Addison Wesley 1996.

The C++ Programming Language 3e, Bjarne Stroustrup. Addison Wesley 1997.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
The C++ Standard Library A Tutorial and Reference (2nd Edition)+cppstdlib-code.zip C++标准(第二版)英文版.pdf 非扫描版+源代码 Prefaceto the SecondEdition xxiii Acknowledgments for the SecondEdition xxiv Prefaceto the FirstEdition xxv Acknowledgments for the FirstEdition xxvi 1 About This Book 1 1.1 Why This Book. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1.2 Before ReadingThis Book. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.3 Styleand Structure of the Book . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.4 How to ReadThis Book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 1.5 Stateof the Art . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 1.6 Example Codeand AdditionalInformation . . . . . . . . . . . . . . . . . . . . . 5 1.7 Feedback . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 2 Introduction to C++ and the StandardLibrary 7 2.1 Historyof the C++ Standards . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 2.1.1 Common Questionsabout the C++11 Standard . . . . . . . . . . . . . . 8 2.1.2 Compatibility between C++98 and C++11 . . . . . . . . . . . . . . . . . 9 2.2 Complexity and Big-O Notation . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 3 New LanguageFeatures 13 3.1 New C++11 Language Features . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 3.1.1 Important MinorSyntax Cleanups . . . . . . . . . . . . . . . . . . . . . 13 3.1.2 AutomaticType Deductionwith auto . . . . . . . . . . . . . . . . . . . 14 3.1.3 UniformInitialization and Initializer Lists . . . . . . . . . . . . . . . . . 15 3.1.4 Range-Basedfor Loops . . . . . . . . . . . . . . . . . . . . . . . . . . 17 3.1.5 MoveSemanticsand Rvalue References . . . . . . . . . . . . . . . . . . 19 viii Contents 3.1.6 New String Literals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 3.1.7 Keyword noexcept . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 3.1.8 Keyword constexpr . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 3.1.9 New Template Features . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 3.1.10 Lambdas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 3.1.11 Keyword decltype . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 3.1.12 New Function Declaration Syntax . . . . . . . . . . . . . . . . . . . . . 32 3.1.13 Scoped Enumerations . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 3.1.14 New FundamentalData Types . . . . . . . . . . . . . . . . . . . . . . . 33 3.2 Old “New” Language Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 3.2.1 ExplicitInitialization for FundamentalTypes . . . . . . . . . . . . . . . 37 3.2.2 Definitionof main() . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 4 GeneralConcepts 39 4.1 Namespace std . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 4.2 Header Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 4.3 Errorand ExceptionHandling . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 4.3.1 Standard ExceptionClasses. . . . . . . . . . . . . . . . . . . . . . . . . 41 4.3.2 Members of ExceptionClasses. . . . . . . . . . . . . . . . . . . . . . . 44 4.3.3 PassingExceptions with Classexception_ptr . . . . . . . . . . . . . . 52 4.3.4 Throwing Standard Exceptions . . . . . . . . . . . . . . . . . . . . . . . 53 4.3.5 Deriving from Standard ExceptionClasses. . . . . . . . . . . . . . . . . 54 4.4 CallableObjects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 4.5 Concurrencyand Multithreading. . . . . . . . . . . . . . . . . . . . . . . . . . . 55 4.6 Allocators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 5 Utilities 59 5.1 Pairs and Tuples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 5.1.1 Pairs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 5.1.2 Tuples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 5.1.3 I/O for Tuples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 5.1.4 Conversions between tuple sandpairs . . . . . . . . . . . . . . . . . . 75 5.2 Smart Pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 5.2.1 Classshared_ptr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 5.2.2 Classweak_ptr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 5.2.3 Misusing Shared Pointers . . . . . . . . . . . . . . . . . . . . . . . . . . 89 5.2.4 Shared and WeakPointersin Detail. . . . . . . . . . . . . . . . . . . . . 92 5.2.5 Classunique_ptr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 Contents ix 5.2.6 Classunique_ptrin Detail . . . . . . . . . . . . . . . . . . . . . . . . 110 5.2.7 Classauto_ptr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113 5.2.8 FinalWordsonSmart Pointers . . . . . . . . . . . . . . . . . . . . . . . 114 5.3 Numeric Limits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115 5.4 Type Traitsand Type Utilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 5.4.1 Purposeof Type Traits . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 5.4.2 Type Traitsin Detail. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125 5.4.3 ReferenceWrappers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132 5.4.4 Function Type Wrappers . . . . . . . . . . . . . . . . . . . . . . . . . . 133 5.5 Auxiliary Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134 5.5.1 Processing the Minimumand Maximum. . . . . . . . . . . . . . . . . . 134 5.5.2 Swapping Two Va l u e s . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136 5.5.3 SupplementaryComparison Operators . . . . . . . . . . . . . . . . . . . 138 5.6 Compile-Time FractionalArithmeticwith Classratio . . . . . . . . . . . . . 140 5.7 Clocks and Timers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143 5.7.1 Overview of the ChronoLibrary . . . . . . . . . . . . . . . . . . . . . . 143 5.7.2 Durations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 5.7.3 Clocks and Timepoints . . . . . . . . . . . . . . . . . . . . . . . . . . . 149 5.7.4 Date and TimeFunctions byC and POSIX . . . . . . . . . . . . . . . . . 157 5.7.5 Blocking with Timers . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160 5.8 Header Files , ,and . . . . . . . . . . . . . . 161 5.8.1 Definitionsin . . . . . . . . . . . . . . . . . . . . . . . . . . 161 5.8.2 Definitionsin . . . . . . . . . . . . . . . . . . . . . . . . . . 162 5.8.3 Definitionsin . . . . . . . . . . . . . . . . . . . . . . . . . . 163 6 The StandardTe m p l a t e Library 165 6.1 STL Components. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 6.2 Containers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167 6.2.1 Sequence Containers . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169 6.2.2 Associative Containers . . . . . . . . . . . . . . . . . . . . . . . . . . . 177 6.2.3 UnorderedContainers . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180 6.2.4 Associative Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185 6.2.5 OtherContainers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187 6.2.6 Container Adapters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188 6.3 Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188 6.3.1 Further Examples of UsingAssociative and UnorderedContainers . . . . 193 6.3.2 Iterator Categories. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198 x Contents 6.4 Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199 6.4.1 Ranges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203 6.4.2 Handling MultipleRanges . . . . . . . . . . . . . . . . . . . . . . . . . 207 6.5 Iterator Adapters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210 6.5.1 Insert Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210 6.5.2 Stream Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212 6.5.3 ReverseIterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214 6.5.4 MoveIterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216 6.6 User-DefinedGenericFunctions . . . . . . . . . . . . . . . . . . . . . . . . . . . 216 6.7 ManipulatingAlgorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217 6.7.1 “Removing”Elements . . . . . . . . . . . . . . . . . . . . . . . . . . . 218 6.7.2 ManipulatingAssociative and UnorderedContainers . . . . . . . . . . . 221 6.7.3 Algorithms versus MemberFunctions . . . . . . . . . . . . . . . . . . . 223 6.8 Functions as AlgorithmArguments . . . . . . . . . . . . . . . . . . . . . . . . . 224 6.8.1 UsingFunctions as AlgorithmArguments . . . . . . . . . . . . . . . . . 224 6.8.2 Predicates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226 6.9 UsingLambdas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229 6.10 Function Objects. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233 6.10.1 Definitionof Function Objects . . . . . . . . . . . . . . . . . . . . . . . 233 6.10.2 PredefinedFunction Objects . . . . . . . . . . . . . . . . . . . . . . . . 239 6.10.3 Binders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241 6.10.4 Function Objectsand Bindersversus Lambdas . . . . . . . . . . . . . . . 243 6.11 Container Elements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244 6.11.1 Requirements for Container Elements . . . . . . . . . . . . . . . . . . . 244 6.11.2 Va l u eSemanticsor ReferenceSemantics. . . . . . . . . . . . . . . . . . 245 6.12 Errors and Exceptions inside the STL . . . . . . . . . . . . . . . . . . . . . . . . 245 6.12.1 ErrorHandling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246 6.12.2 ExceptionHandling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248 6.13 Extendingthe STL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250 6.13.1 Integrating AdditionalTypes . . . . . . . . . . . . . . . . . . . . . . . . 250 6.13.2 Deriving from STL Types . . . . . . . . . . . . . . . . . . . . . . . . . . 251 7 STL Containers 253 7.1 Common Container Abilitiesand Operations . . . . . . . . . . . . . . . . . . . . 254 7.1.1 Container Abilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254 7.1.2 Container Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254 7.1.3 Container Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260 Contents xi 7.2 Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261 7.2.1 Abilitiesof Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261 7.2.2 ArrayOperations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263 7.2.3 Usingarray s as C-StyleArrays . . . . . . . . . . . . . . . . . . . . . . 267 7.2.4 ExceptionHandling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268 7.2.5 TupleInterface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268 7.2.6 Examples of UsingArrays . . . . . . . . . . . . . . . . . . . . . . . . . 268 7.3 Ve c t o r s . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270 7.3.1 Abilitiesof Ve c t o r s . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270 7.3.2 Ve c t o r Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273 7.3.3 UsingVe c t o r sas C-StyleArrays . . . . . . . . . . . . . . . . . . . . . . 278 7.3.4 ExceptionHandling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278 7.3.5 Examples of UsingVe c t o r s . . . . . . . . . . . . . . . . . . . . . . . . . 279 7.3.6 Classvector . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281 7.4 Deques. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283 7.4.1 Abilitiesof Deques. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284 7.4.2 Deque Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285 7.4.3 ExceptionHandling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288 7.4.4 Examples of UsingDeques. . . . . . . . . . . . . . . . . . . . . . . . . 288 7.5 Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290 7.5.1 Abilitiesof Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290 7.5.2 List Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291 7.5.3 ExceptionHandling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296 7.5.4 Examples of UsingLists . . . . . . . . . . . . . . . . . . . . . . . . . . 298 7.6 Forward Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300 7.6.1 Abilitiesof Forward Lists . . . . . . . . . . . . . . . . . . . . . . . . . . 300 7.6.2 Forward List Operations . . . . . . . . . . . . . . . . . . . . . . . . . . 302 7.6.3 ExceptionHandling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311 7.6.4 Examples of UsingForward Lists . . . . . . . . . . . . . . . . . . . . . . 312 7.7 Sets and Multisets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314 7.7.1 Abilitiesof Sets and Multisets . . . . . . . . . . . . . . . . . . . . . . . 315 7.7.2 Setand MultisetOperations. . . . . . . . . . . . . . . . . . . . . . . . . 316 7.7.3 ExceptionHandling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 325 7.7.4 Examples of UsingSets and Multisets . . . . . . . . . . . . . . . . . . . 325 7.7.5 Example of Specifying the Sorting Criterion at Runtime . . . . . . . . . . 328 xii Contents 7.8 Mapsand Multimaps. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331 7.8.1 Abilitiesof Mapsand Multimaps. . . . . . . . . . . . . . . . . . . . . . 332 7.8.2 Map and Multimap Operations . . . . . . . . . . . . . . . . . . . . . . . 333 7.8.3 UsingMapsas Associative Arrays . . . . . . . . . . . . . . . . . . . . . 343 7.8.4 ExceptionHandling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 345 7.8.5 Examples of UsingMapsand Multimaps. . . . . . . . . . . . . . . . . . 345 7.8.6 Example with Maps,Strings,and Sorting Criterion at Runtime . . . . . . 351 7.9 UnorderedContainers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355 7.9.1 Abilitiesof UnorderedContainers . . . . . . . . . . . . . . . . . . . . . 357 7.9.2 Creating and Controlling UnorderedContainers . . . . . . . . . . . . . . 359 7.9.3 OtherOperationsfor UnorderedContainers . . . . . . . . . . . . . . . . 367 7.9.4 The Bucket Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . 374 7.9.5 UsingUnorderedMapsas Associative Arrays . . . . . . . . . . . . . . . 374 7.9.6 ExceptionHandling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 375 7.9.7 Examples of UsingUnorderedContainers . . . . . . . . . . . . . . . . . 375 7.10 OtherSTL Containers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385 7.10.1 Strings as STL Containers . . . . . . . . . . . . . . . . . . . . . . . . . 385 7.10.2 Ordinary C-StyleArrays as STL Containers . . . . . . . . . . . . . . . . 386 7.11 Implementing ReferenceSemantics . . . . . . . . . . . . . . . . . . . . . . . . . 388 7.12 Whento Use WhichContainer . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392 8 STL ContainerMembersin Detail 397 8.1 Type Definitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397 8.2 Create, Copy,and DestroyOperations . . . . . . . . . . . . . . . . . . . . . . . . 400 8.3 Nonmodifying Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403 8.3.1 Size Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403 8.3.2 Comparison Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . 404 8.3.3 Nonmodifying Operationsfor Associative and UnorderedContainers . . . 404 8.4 Assignments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406 8.5 Direct ElementAccess . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408 8.6 Operationsto Generate Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . 410 8.7 Inserting and RemovingElements . . . . . . . . . . . . . . . . . . . . . . . . . . 411 8.7.1 Inserting Single Elements . . . . . . . . . . . . . . . . . . . . . . . . . . 411 8.7.2 Inserting MultipleElements . . . . . . . . . . . . . . . . . . . . . . . . . 416 8.7.3 RemovingElements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417 8.7.4 Resizing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420 Contents xiii 8.8 Special MemberFunctions for Lists and Forward Lists . . . . . . . . . . . . . . . 420 8.8.1 Special MemberFunctions for Lists (and Forward Lists) . . . . . . . . . 420 8.8.2 Special MemberFunctions for Forward Lists Only . . . . . . . . . . . . 423 8.9 Container Policy Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 427 8.9.1 Nonmodifying Policy Functions . . . . . . . . . . . . . . . . . . . . . . 427 8.9.2 ModifyingPolicy Functions . . . . . . . . . . . . . . . . . . . . . . . . 428 8.9.3 Bucket Interface for UnorderedContainers . . . . . . . . . . . . . . . . . 429 8.10 Allocator Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 430 8.10.1 FundamentalAllocator Members . . . . . . . . . . . . . . . . . . . . . . 430 8.10.2 Constructorswith Optional Allocator Parameters . . . . . . . . . . . . . 430 9 STL Iterators 433 9.1 Header Files for Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433 9.2 Iterator Categories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433 9.2.1 Output Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433 9.2.2 Input Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 435 9.2.3 Forward Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436 9.2.4 BidirectionalIterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . 437 9.2.5 Random-Access Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . 438 9.2.6 The Incrementand DecrementProblem of Ve c t o r Iterators . . . . . . . . 440 9.3 Auxiliary Iterator Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441 9.3.1 advance() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441 9.3.2 next()and prev(). . . . . . . . . . . . . . . . . . . . . . . . . . . . . 443 9.3.3 distance() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 445 9.3.4 iter_swap() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 446 9.4 Iterator Adapters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 448 9.4.1 ReverseIterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 448 9.4.2 Insert Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 454 9.4.3 Stream Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 460 9.4.4 MoveIterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 466 9.5 Iterator Traits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 466 9.5.1 WritingGenericFunctions for Iterators . . . . . . . . . . . . . . . . . . . 468 9.6 WritingUser-DefinedIterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . 471 xiv Contents 10 STL Function Objectsand UsingLambdas 475 10.1 The Conceptof Function Objects . . . . . . . . . . . . . . . . . . . . . . . . . . 475 10.1.1 Function Objectsas Sorting Criteria . . . . . . . . . . . . . . . . . . . . 476 10.1.2 Function Objectswith Internal State . . . . . . . . . . . . . . . . . . . . 478 10.1.3 The Return Va l u eof for_each() . . . . . . . . . . . . . . . . . . . . . 482 10.1.4 Predicatesversus Function Objects. . . . . . . . . . . . . . . . . . . . . 483 10.2 PredefinedFunction Objectsand Binders . . . . . . . . . . . . . . . . . . . . . . 486 10.2.1 PredefinedFunction Objects . . . . . . . . . . . . . . . . . . . . . . . . 486 10.2.2 Function Adapters and Binders. . . . . . . . . . . . . . . . . . . . . . . 487 10.2.3 User-DefinedFunction Objectsfor Function Adapters . . . . . . . . . . . 495 10.2.4 Deprecated Function Adapters . . . . . . . . . . . . . . . . . . . . . . . 497 10.3 UsingLambdas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 499 10.3.1 Lambdas versus Binders . . . . . . . . . . . . . . . . . . . . . . . . . . 499 10.3.2 Lambdas versus StatefulFunction Objects. . . . . . . . . . . . . . . . . 500 10.3.3 Lambdas Calling Global and MemberFunctions . . . . . . . . . . . . . . 502 10.3.4 Lambdas as HashFunction, Sorting,or Equivalence Criterion . . . . . . . 504 11 STL Algorithms 505 11.1 AlgorithmHeader Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 505 11.2 AlgorithmOverview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 505 11.2.1 A BriefIntroduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 506 11.2.2 Classification of Algorithms . . . . . . . . . . . . . . . . . . . . . . . . 506 11.3 Auxiliary Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 517 11.4 The for_each()Algorithm. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 519 11.5 Nonmodifying Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 524 11.5.1 Counting Elements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 524 11.5.2 Minimumand Maximum. . . . . . . . . . . . . . . . . . . . . . . . . . 525 11.5.3 SearchingElements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 528 11.5.4 Comparing Ranges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 542 11.5.5 Predicatesfor Ranges . . . . . . . . . . . . . . . . . . . . . . . . . . . . 550 11.6 ModifyingAlgorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 557 11.6.1 Copying Elements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 557 11.6.2 MovingElements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 561 11.6.3 Transforming and Combining Elements . . . . . . . . . . . . . . . . . . 563 11.6.4 Swapping Elements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 566 11.6.5 AssigningNew Va l u e s . . . . . . . . . . . . . . . . . . . . . . . . . . . 568 11.6.6 ReplacingElements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 571 Contents xv 11.7 RemovingAlgorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 575 11.7.1 RemovingCertain Va l u e s . . . . . . . . . . . . . . . . . . . . . . . . . . 575 11.7.2 RemovingDuplicates . . . . . . . . . . . . . . . . . . . . . . . . . . . . 578 11.8 Mutating Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 583 11.8.1 Reversingthe Orderof Elements . . . . . . . . . . . . . . . . . . . . . . 583 11.8.2 Rotating Elements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 584 11.8.3 PermutingElements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 587 11.8.4 Shuffling Elements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 589 11.8.5 MovingElements to the Front . . . . . . . . . . . . . . . . . . . . . . . 592 11.8.6 Partition into Two Subranges . . . . . . . . . . . . . . . . . . . . . . . . 594 11.9 Sorting Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 596 11.9.1 Sorting AllElements . . . . . . . . . . . . . . . . . . . . . . . . . . . . 596 11.9.2 Partial Sorting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 599 11.9.3 Sorting Accordingto the n th Element . . . . . . . . . . . . . . . . . . . 602 11.9.4 HeapAlgorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 604 11.10 Sorted-Range Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 608 11.10.1SearchingElements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 608 11.10.2MergingElements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 614 11.11 Numeric Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 623 11.11.1Processing Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 623 11.11.2Converting Relativeand Absolute Va l u e s . . . . . . . . . . . . . . . . . . 627 12 SpecialContainers 631 12.1 Stacks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 632 12.1.1 The Core Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 633 12.1.2 Example of UsingStacks . . . . . . . . . . . . . . . . . . . . . . . . . . 633 12.1.3 A User-DefinedStackClass. . . . . . . . . . . . . . . . . . . . . . . . . 635 12.1.4 Classstack in Detail . . . . . . . . . . . . . . . . . . . . . . . . . . 637 12.2 Queues. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 638 12.2.1 The Core Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 639 12.2.2 Example of UsingQueues . . . . . . . . . . . . . . . . . . . . . . . . . 640 12.2.3 A User-DefinedQueue Class . . . . . . . . . . . . . . . . . . . . . . . . 641 12.2.4 Classqueue in Detail . . . . . . . . . . . . . . . . . . . . . . . . . . 641 12.3 PriorityQueues. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 641 12.3.1 The Core Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 643 12.3.2 Example of UsingPriorityQueues. . . . . . . . . . . . . . . . . . . . . 643 12.3.3 Classpriority_queue in Detail . . . . . . . . . . . . . . . . . . . . 644 xvi Contents 12.4 Container Adapters in Detail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 645 12.4.1 Type Definitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 645 12.4.2 Constructors. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 646 12.4.3 SupplementaryConstructorsfor PriorityQueues. . . . . . . . . . . . . . 646 12.4.4 Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 647 12.5 Bitsets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 650 12.5.1 Examples of UsingBitsets . . . . . . . . . . . . . . . . . . . . . . . . . 651 12.5.2 Classbitsetin Detail . . . . . . . . . . . . . . . . . . . . . . . . . . . 653 13 Strings 655 13.1 Purposeof the String Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 656 13.1.1 A First Example: Extractinga Temporary Filename . . . . . . . . . . . . 656 13.1.2 A Second Example: ExtractingWordsand PrintingThemBackward . . . 660 13.2 Description of the String Classes . . . . . . . . . . . . . . . . . . . . . . . . . . 663 13.2.1 String Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 663 13.2.2 OperationOverview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 666 13.2.3 Constructorsand Destructor . . . . . . . . . . . . . . . . . . . . . . . . 667 13.2.4 Strings and C-Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . 668 13.2.5 Size and Capacity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 669 13.2.6 ElementAccess . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 671 13.2.7 Comparisons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 672 13.2.8 Modifiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 673 13.2.9 Substringsand String Concatenation . . . . . . . . . . . . . . . . . . . . 676 13.2.10Input/Output Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . 677 13.2.11Searchingand Finding . . . . . . . . . . . . . . . . . . . . . . . . . . . 678 13.2.12The Va l u enpos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 680 13.2.13Numeric Conversions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 681 13.2.14Iterator Supportfor Strings . . . . . . . . . . . . . . . . . . . . . . . . . 684 13.2.15Internationalization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 689 13.2.16Performance. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 692 13.2.17Strings and Ve c t o r s . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 692 13.3 String Classin Detail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 693 13.3.1 Type Definitionsand StaticVa l u e s . . . . . . . . . . . . . . . . . . . . . 693 13.3.2 Create, Copy,and DestroyOperations . . . . . . . . . . . . . . . . . . . 694 13.3.3 Operationsfor Size and Capacity . . . . . . . . . . . . . . . . . . . . . . 696 13.3.4 Comparisons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 697 13.3.5 Character Access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 699 13.3.6 GeneratingC-Strings and Character Arrays . . . . . . . . . . . . . . . . 700 Contents xvii 13.3.7 ModifyingOperations. . . . . . . . . . . . . . . . . . . . . . . . . . . . 700 13.3.8 Searchingand Finding . . . . . . . . . . . . . . . . . . . . . . . . . . . 708 13.3.9 Substringsand String Concatenation . . . . . . . . . . . . . . . . . . . . 711 13.3.10Input/Output Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . 712 13.3.11Numeric Conversions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 713 13.3.12GeneratingIterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 714 13.3.13Allocator Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 715 14 RegularExpressions 717 14.1 The Regex Matchand Search Interface . . . . . . . . . . . . . . . . . . . . . . . 717 14.2 Dealingwith Subexpressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 720 14.3 Regex Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 726 14.4 Regex Token Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 727 14.5 ReplacingRegularExpressions . . . . . . . . . . . . . . . . . . . . . . . . . . . 730 14.6 Regex Flags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 732 14.7 Regex Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 735 14.8 The Regex ECMAScriptGrammar . . . . . . . . . . . . . . . . . . . . . . . . . 738 14.9 OtherGrammars . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 739 14.10 BasicRegex Signaturesin Detail . . . . . . . . . . . . . . . . . . . . . . . . . . 740 15 Input/Output UsingStreamClasses 743 15.1 Common Background of I/O Streams . . . . . . . . . . . . . . . . . . . . . . . . 744 15.1.1 Stream Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 744 15.1.2 Stream Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 744 15.1.3 Global Stream Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . 745 15.1.4 Stream Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 745 15.1.5 Manipulators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 746 15.1.6 A Simple Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 746 15.2 FundamentalStream Classesand Objects. . . . . . . . . . . . . . . . . . . . . . 748 15.2.1 Classes and ClassHierarchy . . . . . . . . . . . . . . . . . . . . . . . . 748 15.2.2 Global Stream Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . 751 15.2.3 Header Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 752 15.3 Standard Stream Operators <> . . . . . . . . . . . . . . . . . . . . . . . . 753 15.3.1 Output Operator <> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 754 15.3.3 Input/Output of Special Types . . . . . . . . . . . . . . . . . . . . . . . 755 xviii Contents 15.4 Stateof Streams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 758 15.4.1 Constants for the Stateof Streams . . . . . . . . . . . . . . . . . . . . . 758 15.4.2 MemberFunctions Accessingthe Stateof Streams. . . . . . . . . . . . . 759 15.4.3 Stream Stateand BooleanConditions . . . . . . . . . . . . . . . . . . . 760 15.4.4 Stream Stateand Exceptions . . . . . . . . . . . . . . . . . . . . . . . . 762 15.5 Standard Input/Output Functions . . . . . . . . . . . . . . . . . . . . . . . . . . 767 15.5.1 MemberFunctions for Input . . . . . . . . . . . . . . . . . . . . . . . . 768 15.5.2 MemberFunctions for Output . . . . . . . . . . . . . . . . . . . . . . . 771 15.5.3 Example Uses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 772 15.5.4 sentryObjects. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 772 15.6 Manipulators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 774 15.6.1 Overview of AllManipulators . . . . . . . . . . . . . . . . . . . . . . . 774 15.6.2 How ManipulatorsWork . . . . . . . . . . . . . . . . . . . . . . . . . . 776 15.6.3 User-DefinedManipulators. . . . . . . . . . . . . . . . . . . . . . . . . 777 15.7 Formatting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 779 15.7.1 Format Flags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 779 15.7.2 Input/Output Format of BooleanVa l u e s . . . . . . . . . . . . . . . . . . 781 15.7.3 FieldWidth, Fill Character,and Adjustment . . . . . . . . . . . . . . . . 781 15.7.4 PositiveSign and UppercaseLetters . . . . . . . . . . . . . . . . . . . . 784 15.7.5 Numeric Base . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 785 15.7.6 Floating-Point Notation . . . . . . . . . . . . . . . . . . . . . . . . . . . 787 15.7.7 GeneralFormatting Definitions . . . . . . . . . . . . . . . . . . . . . . . 789 15.8 Internationalization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 790 15.9 File Access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 791 15.9.1 File Stream Classes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 791 15.9.2 Rvalue and MoveSemanticsfor File Streams . . . . . . . . . . . . . . . 795 15.9.3 File Flags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 796 15.9.4 RandomAccess . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 799 15.9.5 UsingFile Descriptors . . . . . . . . . . . . . . . . . . . . . . . . . . . 801 15.10 Stream Classesfor Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 802 15.10.1String Stream Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 802 15.10.2MoveSemanticsfor String Streams. . . . . . . . . . . . . . . . . . . . . 806 15.10.3char* Stream Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 807 15.11 Input/Output Operators for User-DefinedTypes . . . . . . . . . . . . . . . . . . . 810 15.11.1Implementing Output Operators . . . . . . . . . . . . . . . . . . . . . . 810 15.11.2Implementing Input Operators . . . . . . . . . . . . . . . . . . . . . . . 812 15.11.3Input/Output UsingAuxiliary Functions . . . . . . . . . . . . . . . . . . 814 Contents xix 15.11.4User-DefinedFormat Flags . . . . . . . . . . . . . . . . . . . . . . . . . 815 15.11.5Conventionsfor User-DefinedInput/Output Operators . . . . . . . . . . . 818 15.12 Connecting Input and Output Streams . . . . . . . . . . . . . . . . . . . . . . . . 819 15.12.1Loose Coupling Usingtie() . . . . . . . . . . . . . . . . . . . . . . . . 819 15.12.2TightCoupling UsingStream Buffers . . . . . . . . . . . . . . . . . . . 820 15.12.3Redirecting Standard Streams. . . . . . . . . . . . . . . . . . . . . . . . 822 15.12.4Streamsfor Readingand Writing. . . . . . . . . . . . . . . . . . . . . . 824 15.13 The Stream Buffer Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 826 15.13.1The Stream Buffer Interfaces . . . . . . . . . . . . . . . . . . . . . . . . 826 15.13.2Stream Buffer Iterators . . . . . . . . . . . . . . . . . . . . . . . . . . . 828 15.13.3User-DefinedStream Buffers . . . . . . . . . . . . . . . . . . . . . . . . 832 15.14 PerformanceIssues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 844 15.14.1Synchronization with C’sStandard Streams . . . . . . . . . . . . . . . . 845 15.14.2Buffering in Stream Buffers . . . . . . . . . . . . . . . . . . . . . . . . . 845 15.14.3UsingStream Buffers Directly . . . . . . . . . . . . . . . . . . . . . . . 846 16 Internationalization 849 16.1 Character Encodingsand Character Sets . . . . . . . . . . . . . . . . . . . . . . . 850 16.1.1 Multibyte and Wide-CharacterText . . . . . . . . . . . . . . . . . . . . . 850 16.1.2 Different Character Sets . . . . . . . . . . . . . . . . . . . . . . . . . . . 851 16.1.3 Dealingwith Character Sets in C++ . . . . . . . . . . . . . . . . . . . . 852 16.1.4 Character Traits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 853 16.1.5 Internationalization of Special Characters . . . . . . . . . . . . . . . . . 857 16.2 The Conceptof Locales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 857 16.2.1 UsingLocales. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 858 16.2.2 Locale Facets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 864 16.3 Localesin Detail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 866 16.4 Facets in Detail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 869 16.4.1 Numeric Formatting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 870 16.4.2 Monetary Formatting . . . . . . . . . . . . . . . . . . . . . . . . . . . . 874 16.4.3 Timeand Date Formatting . . . . . . . . . . . . . . . . . . . . . . . . . 884 16.4.4 Character Classification and Conversion . . . . . . . . . . . . . . . . . . 891 16.4.5 String Collation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 904 16.4.6 Internationalized Messages . . . . . . . . . . . . . . . . . . . . . . . . . 905 xx Contents 17 Numerics 907 17.1 RandomNumbers and Distributions. . . . . . . . . . . . . . . . . . . . . . . . . 907 17.1.1 A First Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 908 17.1.2 Engines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 912 17.1.3 Enginesin Detail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 915 17.1.4 Distributions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 917 17.1.5 Distributionsin Detail . . . . . . . . . . . . . . . . . . . . . . . . . . . . 921 17.2 Complex Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 925 17.2.1 Classcomplex in General . . . . . . . . . . . . . . . . . . . . . . . . 925 17.2.2 Examples UsingClasscomplex . . . . . . . . . . . . . . . . . . . . . 926 17.2.3 Operationsfor Complex Numbers . . . . . . . . . . . . . . . . . . . . . 928 17.2.4 Classcomplex in Detail . . . . . . . . . . . . . . . . . . . . . . . . . 935 17.3 Global Numeric Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 941 17.4 Va l a r r a y s . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 943 18 Concurrency 945 18.1 The High-Level Interface: async() and Futures . . . . . . . . . . . . . . . . . . 946 18.1.1 A First Example Usingasync() and Futures . . . . . . . . . . . . . . . 946 18.1.2 AnExample of Waitingfor Two Tasks . . . . . . . . . . . . . . . . . . . 955 18.1.3 Shared Futures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 960 18.2 The Low-Level Interface: Threadsand Promises . . . . . . . . . . . . . . . . . . 964 18.2.1 Classstd::thread . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 964 18.2.2 Promises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 969 18.2.3 Classpackaged_task . . . . . . . . . . . . . . . . . . . . . . . . . . 972 18.3 Startinga Thread in Detail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 973 18.3.1 async() in Detail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 974 18.3.2 Futuresin Detail. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 975 18.3.3 Shared Futuresin Detail. . . . . . . . . . . . . . . . . . . . . . . . . . . 976 18.3.4 Classstd::promise in Detail . . . . . . . . . . . . . . . . . . . . . . . 977 18.3.5 Classstd::packaged_task in Detail . . . . . . . . . . . . . . . . . . . 977 18.3.6 Classstd::thread in Detail . . . . . . . . . . . . . . . . . . . . . . . . 979 18.3.7 Namespace this_thread . . . . . . . . . . . . . . . . . . . . . . . . . 981 18.4 Synchronizing Threads, or the Problem of Concurrency . . . . . . . . . . . . . . 982 18.4.1 Bewareof Concurrency! . . . . . . . . . . . . . . . . . . . . . . . . . . 982 18.4.2 The Reason for the Problem of Concurrent Data Access . . . . . . . . . . 983 18.4.3 WhatExactlyCan GoWrong (the Extent of the Problem) . . . . . . . . . 983 18.4.4 The Features to Solvethe Problems . . . . . . . . . . . . . . . . . . . . . 987 Contents xxi 18.5 Mutexesand Locks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 989 18.5.1 UsingMutexesand Locks . . . . . . . . . . . . . . . . . . . . . . . . . . 989 18.5.2 Mutexesand Locks in Detail . . . . . . . . . . . . . . . . . . . . . . . . 998 18.5.3 Calling Oncefor MultipleThreads . . . . . . . . . . . . . . . . . . . . . 1000 18.6 ConditionVa r i a b l e s . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1003 18.6.1 Purposeof ConditionVa r i a b l e s . . . . . . . . . . . . . . . . . . . . . . . 1003 18.6.2 A First Complete Example for ConditionVa r i a b l e s . . . . . . . . . . . . 1004 18.6.3 UsingConditionVa r i a b l e s to Implement a Queue for MultipleThreads . . 1006 18.6.4 ConditionVa r i a b l e s in Detail . . . . . . . . . . . . . . . . . . . . . . . . 1009 18.7 Atomics. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1012 18.7.1 Example of UsingAtomics . . . . . . . . . . . . . . . . . . . . . . . . . 1012 18.7.2 Atomicsand TheirHigh-Level Interface in Detail . . . . . . . . . . . . . 1016 18.7.3 The C-StyleInterface of Atomics . . . . . . . . . . . . . . . . . . . . . . 1019 18.7.4 The Low-Level Interface of Atomics . . . . . . . . . . . . . . . . . . . . 1019 19 Allocators 1023 19.1 UsingAllocatorsas an Application Programmer . . . . . . . . . . . . . . . . . . 1023 19.2 A User-DefinedAllocator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1024 19.3 UsingAllocatorsas a LibraryProgrammer . . . . . . . . . . . . . . . . . . . . . 1026 Bibliography 1031 Newsgroups and Forums . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1031 Books and Web Sites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1032 Index 1037 This page intentionally left blank
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值