Visual CPP Template Library
Visual CPP Template Library
2 Standard Template
Library Tutorial
Kalindi Sanghrajka, Rick Troemel, Nevenka Subotic-Burina, and Linda Koontz
October 1996
CONTENTS
5. Sequence Containers
6. Associative Containers
7. Iterators
8. Container Adapters
This tutorial will provide an overview of the Standard C++ Libraries as implemented in
Microsoft® Visual C++® version 4.2, with an emphasis on the Standard Template
Library. Upon completion of this tutorial, you will be able to:
• Write simple programs using Visual C++ version 4.2. that use the Standard
Template Library components.
1.2 Prerequisites
This tutorial assumes that you understand basic C++ programming. It is also necessary to
have a good understanding of C++ templates.
Every C++ programmer has probably, at one time or another, written a linked list or set,
searching and sorting routines. Most likely, the programmer has re-invented the wheel for
every new user-defined data type. Design changes are not easy to implement in such
cases. Maintaining such code is not very easy, either.
If the common programming components were part of the C++ language, programmers
would not need to "re-invent the wheel."
Finally, the C++ language provides you with general purpose components for common
programming tasks through the Standard C++ Library. The Standard C++ Library
provides powerful and flexible containers, programmable algorithms, and other
components that are efficient and extensible.
• The Standard Template Library (STL): Provides a C++ program access to the
most widely used algorithms and data structures. STL headers can be grouped into
three major organizing concepts: containers, iterators, and algorithms. Containers
are template classes that provide powerful and flexible ways to organize data: for
example, vectors, lists, sets and maps. Iterators are the glue that pastes together
algorithms and containers. STL provides a large set of programmable algorithms
to handle sorting, searching, and other common tasks.
Microsoft® Visual C++® version 4.2 provides the Standard C++ Library facilities
through included files and associated static and dynamic libraries.
A C++ program can use the different components of the Standard C++ Library by
including the required header and linking with the appropriate static or dynamic library.
Tables 1 and 2 list all the Standard C++ Library headers and the associated static and
dynamic libraries provided by Visual C++ 4.2.
Note The Standard C++ Library headers do not have an “.h” extension. This is in
accordance with the latest C++ working papers.
Visual C++ 4.2 includes the following static and dynamic libraries (in addition to the
Microsoft Class Library [MFC]):
Table 2. Static and Dynamic Libraries Included with Microsoft Visual C++ 4.2
Case 1. Consider the following sample C++ program where test.cpp uses the Standard
C++ Library iostream to print "Hello World".
// test.cpp
#include <iostream>
void main()
{
cout << "Hello World" << endl ;
}
In Case 1, test.cpp used the Standard C++ Library input/output component to print "Hello
World." The program just includes the Standard C++ Library header <iostream>. When
compiling the program, specify a run-time library option: /ML[d],/MT[d], or /MD[d]. The
program will then link with a basic run-time library (for example, LIBC.LIB with the
/ML option) and a Standard C++ Library (for example, LIBCP.LIB with the /ML option).
The /GX option enables exception handling. Exception handling must be enabled for any
programs that use the Standard C++ Library.
It is important to remember that starting with Visual C++ 4.2, a C++ program, depending
on the run-time library compiler option specified (/ML[d],/MT[d], or /MD[d]), will
always link with one Basic C run-time library and, depending on headers included, will
link with either a Standard C++ Library (as in the case 1), an old iostream library (as in
Case 3), or neither (as in Case 2).
// test.cpp
void main()
{
}
// test.cpp
#include <iostream.h>
void main()
{
}
Many C++ programs use common data structures such as stacks, queues, and lists.
Imagine a program that requires a queue of customers and a queue of messages. You
could easily implement a queue of customers, and then take the existing code and
implement a queue of messages. If the program grows and there is a need for a queue of
orders you could take the queue of messages and convert it to a queue of orders. But what
if you need to make some changes to the queue implementation? This would not be a
very easy task because the code has been duplicated in many places. Re-inventing source
code is not an intelligent approach in an object-oriented environment that encourages re-
usability. It seems to make more sense to implement a queue that can contain any
arbitrary type rather than duplicating code. How does one do that? The answer is to use
Type Parameterization, more commonly referred to as Templates.
C++ templates allow one to implement a generic Queue<T> template that has a T type
parameter. T can be replaced with actual types. For example, if the type parameter is
<Customers>, C++ will generate the class Queue<Customers>. Therefore, changing the
implementation of the Queue becomes relatively simple. In our example, once the
changes are implemented in the template Queue<T>, they are immediately reflected in
the classes Queue<Customers>, Queue<Messages>, and Queue<Orders>.
Templates are very useful when implementing generic constructs such as vectors, stacks,
lists, and queues that can be used with any arbitrary type. C++ templates provide a way to
reuse source code, as opposed to inheritance and composition, which provide a way to
reuse object code.
C++ provides two types of templates: class templates and function templates. Use
function templates to write generic functions: for example, searching and sorting routines
that can be used with arbitrary types. The Standard Template Library generic algorithms
have been implemented as function templates and the containers have been implemented
as class templates.
3.2 Class Templates
A class template definition looks like a regular class definition, except it is prefixed by
the keyword template. For example, here is the definition of a class template for a stack:
class Stack
{
public:
Stack(int = 10) ;
~Stack() { delete [] stackPtr ; }
int push(const T&);
int pop(T&) ;
int isEmpty()const { return top == -1 ; }
int isFull() const { return top == size - 1 ; }
private:
int size ; // number of elements on Stack.
int top ;
T* stackPtr ;
} ;
T is any type parameter, for example, Stack<Tokens>, where Token is a user defined
class. T does not have to be a class type as implied by the keyword class. For example,
Stack<int> and Stack<Message*> are valid instantiations, even though int and
Message* are not classes.
While implementing class-template member functions, the definitions are prefixed by the
keyword template. Here is the complete implementation of the Stack class template:
//stack.h
#pragma once
class Stack
{
public:
Stack(int = 10) ;
~Stack() { delete [] stackPtr ; }
int push(const T&);
int pop(T&) ; // pop an element off the stack
int isEmpty()const { return top == -1 ; }
int isFull() const { return top == size - 1 ; }
private:
int size ; // Number of elements on Stack
int top ;
T* stackPtr ;
} ;
Stack<T>::Stack(int s)
{
size = s > 0 && s < 1000 ? s : 10 ;
top = -1 ; // initialize stack
stackPtr = new T[size] ;
}
{
if (!isFull())
{
stackPtr[++top] = item ;
return 1 ; // push successful
}
return 0 ; // push unsuccessful
}
{
if (!isEmpty())
{
popValue = stackPtr[top--] ;
return 1 ; // pop successful
}
return 0 ; // pop unsuccessful
}
Using a class template is very easy. Create the required classes by plugging in the actual
type for the type parameters. This process is commonly known as instantiating a class.
Here is a sample driver class that uses the Stack class template:
#include <iostream>
#include “stack.h”
void main()
{
typedef Stack<float> FloatStack ;
FloatStack fs(5) ;
float f = 1.1 ;
cout << "Pushing elements onto fs" << endl ;
while (fs.push(f))
{
cout << f << ' ' ;
f += 1.1 ;
}
cout << endl << "Stack Full." << endl
<< endl << "Popping elements from fs" << endl ;
while (fs.pop(f))
cout << f << ' ' ;
cout << endl << "Stack Empty" << endl ;
cout << endl ;
IntStack is ;
int i = 1.1 ;
cout << "Pushing elements onto is" << endl ;
while (is.push(i))
{
cout << i << ' ' ;
i += 1 ;
}
cout << endl << "Stack Full" << endl
<< endl << "Popping elements from is" << endl ;
while (is.pop(i))
cout << i << ' ' ;
cout << endl << "Stack Empty" << endl ;
}
In the above example we defined a class template Stack. In the driver program we
instantiated a Stack of float (FloatStack) and a Stack of int(IntStack). Once the
template classes are instantiated, you can instantiate objects of that type (for example, fs
and is.)
A very good programming practice is to use typedef while instantiating template classes.
Then throughout the program, one can use the typedef name. There are two advantages:
• typedefs are very useful when “templates of templates” are used. For example,
when instantiating an int STL vector, you could use:
• typedef vector<int, allocator<int> > INTVECTOR ;
• If the template definition changes, simply change the typedef definition.
This practice is especially helpful when using STL components. There are many
implementations of STL available, some of which are incompatible. The implementation
in Visual C++ 4.2 may change in future versions. For example, currently the definition of
the vector required you to specify an allocator parameter:
In a future version, the second parameter may not be required, for example,
To perform identical operation for each type of data compactly and conveniently, use
function templates. You can write a single function template definition. Based on the
argument types provided in calls to the function, the compiler automatically instantiates
separate object code functions to handle each type of call appropriately. The STL
algorithms are implemented as function templates.
Function templates are implemented like regular functions, except they are prefixed with
the keyword template. Using function templates is very easy; just use them like regular
functions. Here is a sample with a function template:
#include <iostream>
//max returns the maximum of the two elements
template <class T>
T max(T a, T b)
{
return a > b ? a : b ;
}
void main()
{
cout << "max(10, 15) = " << max(10, 15) << endl ;
cout << "max('k', 's') = " << max('k', 's') << endl ;
cout << "max(10.1, 15.2) = " << max(10.1, 15.2) << endl ;
}
max(10, 15) = 15
max('k', 's') = s
max(10.1, 15.2) = 15.2
#include <iostream.h>
//max returns the maximum of the two elements of type T, where T is a
//class or data type for which operator> is defined.
template <class T>
T max(T a, T b)
{
return a > b ? a : b ;
}
void main()
{
cout << "max(10, 15) = " << max(10, 15) << endl ;
cout << "max('k', 's') = " << max('k', 's') << endl ;
cout << "max(10.1, 15.2) = " << max(10.1, 15.2) << endl ;
cout << "max(\"Aladdin\", \"Jasmine\") = " << max("Aladdin",
"Jasmine") << endl ;
}
max(10, 15) = 15
max('k', 's') = s
max(10.1, 15.2) = 15.2
max("Aladdin", "Jasmine") = Aladdin
Not quite the expected results! Why did that happen? The function call max(“Aladdin”,
“Jasmine”) causes the compiler to generate code for max(char*, char*), which compares
the addresses of the strings! To correct special cases like these or to provide more
efficient implementations for certain types, one can use template specializations. The
above example can be rewritten with specialization as follows:
#include <iostream.h>
#include <string.h>
//max returns the maximum of the two elements
template <class T>
T max(T a, T b)
{
return a > b ? a : b ;
}
// Specialization of max for char*
char* max(char* a, char* b)
{
return strcmp(a, b) > 0 ? a : b ;
}
void main()
{
cout << "max(10, 15) = " << max(10, 15) << endl ;
cout << "max('k', 's') = " << max('k', 's') << endl ;
cout << "max(10.1, 15.2) = " << max(10.1, 15.2) << endl ;
cout << "max(\"Aladdin\", \"Jasmine\") = " << max("Aladdin",
"Jasmine") << endl ;
}
max(10, 15) = 15
max('k', 's') = s
max(10.1, 15.2) = 15.2
max("Aladdin", "Jasmine") = Jasmine
The Stack class template, described in the previous section, used only type parameters in
the template header. It is also possible to use nontype parameters. For example, the
template header could be modified to take an int elements parameter as follows:
could instantiate (at compile time) a 100 element Stack template class named
mostRecentSalesFigures (of float values); this template class would be of type
Stack<float, 100>.
C++ allows you to specify a default template parameter, so the definition could now look
like:
Stack<> mostRecentSalesFigures ;
would instantiate (at compile time) a 100 element Stack template class named
mostRecentSalesFigures (of float values); this template class would be of type
Stack<float, 100>.
If you specify a default template parameter for any formal parameter, the rules are the
same as for functions and default parameters. Once a default parameter is declared, all
subsequent parameters must have defaults.
The following example demonstrates member templates. When you define a class
template or a function template as a member of a class, it is called a member template.
Visual C++ 4.2 does not support member templates.
class MyAllocator
{
int size ;
template class<T> class types; // member class template
template class<T> print(T type) ; // member function template
} ;
The Standard Template Library is a part of the Standard C++ Library. Every C++
programmer at one time or another has implemented common data structures such as a
list or queue, and common algorithms such as binary search, sort, and so on. Through
STL, C++ gives programmers a set of carefully designed generic data structures and
algorithms. The generic data structures and algorithms are parameterized types
(templates) that require only plugging in of actual types to be ready for use. Finally, STL
brings to C++ the long promised dream of re-usable software components.
The STL components are well crafted solutions, which are efficient in code space and
execution time.
• Algorithms are generic functions that handle common tasks such as searching,
sorting, comparing, and editing.
Find, search, merge, count, reverse, and sort, are some of the algorithms provided
by STL. For a complete list of algorithms refer to the documentation.
• Iterators are generalized pointers and act as the glue between containers and
algorithms. STL algorithms are written in terms of iterator parameters, and STL
containers provide iterators that can be plugged into the algorithms.
STL provides the following iterators: input, output, forward, bidirectional and
random access, ostream_iterator, and istream_iterator.
• Function objects are objects of any class or struct that overload the function call
operator(). Most STL algorithms accept a function object as a parameter that can
change the default behavior of the algorithm.
STL defines function objects for basic arithmetic operations such as addition,
subtraction, multiplication, and division. The associated function object types are
plus, minus, times, and divides.
STL also provides function objects for built-in operations such as unary, logical,
bitwise, and comparison operators. The associated function object types are
modulus, negate, equal_to, not_equal_to, greater, less, greater_equal,
less_equal, logical_and, logical_or, and logical_not.
• Function adapters provided by STL include not1, not2, bind1st, and bind2nd.
These very general components are designed to "plug together" in myriad different useful
ways to produce the kind of larger and more specialized components required by
programs.
• When an object is used with an STL container, it is copied (the copy constructor is
called) first and the copy is what is actually inserted into the container.
This means an object held by an STL container must have a copy constructor.
• When an object is removed from an STL container, the object is destroyed (the
destructor is called).
• Many STL components rely on making comparisons of the objects they hold (<,
<=, >, >=, ==, !=).
This means the comparison operators must be defined for objects used with an
STL component.
• Some STL components modify the value of an object. This is accomplished using
the assignment operator.
This means the assignment operator ( = ) must be defined for objects used with an
STL component.
The header file <utility> defines global versions of the <=, >, >=, and != operators, which
are all defined in terms of the < and ==. Therefore, if only the < and == operators are
defined, the rest are defined "for free" (if any of the rest are explicitly defined for an
object, the explicit definition will override the global definition).
In general, it is assumed that objects to be used with STL containers have at least the
following:
• A copy constructor.
• An assignment operator ( = ).
5. Sequence Containers
Sequence containers store and retrieve their data in a sequential fashion. There are three
different sequence containers defined in STL: vector, deque and list.
5.1 Vector
#include <vector>
vector<class TYPE, allocator<class TYPE> >
A vector is similar to a normal C array, except that it can change size automatically as
needed. Data access or modification is random and can be accomplished via operator[].
Insertion or erasure is efficient at the end only. Insertion or erasure of data at the
beginning or in the middle requires shifting the entire array. Therefore, insertion or
erasure anywhere but at the end is a linear operation, meaning that the time to execute the
operation is a function of the number of elements that must be shifted right or left.
Insertion or erasure at the end is a constant operation, meaning that the time to execute
the operation will remain unchanged regardless of how many (or how few) elements are
in the array.
The following function declares a vector of 10 ints, fills the vector with the values 0 - 9,
and then prints the values.
Output of somefunct:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
See APPENDIX D for an explanation of the allocator class (second template parameter
above).
5.2 Deque
#include <deque>
deque<class TYPE, allocator<class TYPE> >
A deque is similar to a vector, except that insertion or erasure is efficient at either the
beginning or the end. Like a vector, data access or modification is random and can be
accomplished via operator[]. Insertion or erasure at either the beginning or the end is a
constant operation, meaning that the time to execute the operation will remain the same,
regardless of how many elements are in the array. Insertion or erasure anywhere in the
middle is a linear operation, meaning that the time to execute the operation is a function
of the number of items that must be shifted right or left. A deque will generate larger,
slower code than a vector. In general, a vector should be used if efficient insertion/erasure
at the beginning of the array is not required and a deque should be used if it is.
The following function declares a deque of ints, fills the deque with the values 0-9,
inserting each new value at the beginning, then prints the values.
Output of somefunct:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
5.3 List
#include <list>
list<class TYPE, allocator<class TYPE> >
A list, like a vector or a deque, is an extensible array. Lists are implemented as doubly
linked lists. Therefore, insertion or erasure at any point in the array is a constant
operation, meaning that the time to execute the operation will remain the same, regardless
of how many elements are in the list. The penalty for using a list instead of a vector or a
deque is paid in data access. There is no random access (no operator[]) for a list, meaning
that accessing the nth object in a list requires "surfing" from the beginning of the list
through N-1 objects. The following function declares a list of ints, fills the list with the
values 0-9, inserting each new value at the beginning, and then prints the values.
Output of somefunct:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
6. Associative Containers
Associative containers store and retrieve their objects according to an association with
each other. In other words, the data is stored and retrieved in a sorted order. Therefore,
associative containers rely heavily upon comparison operators. There are four different
associative containers defined in the STL. They are: set, multiset, map and multimap.
A set is optimized for fast associative lookup. For lookup purposes, objects are matched
using operator==. Objects are ordered within the set according to the user-defined
comparator object (the second template argument). The comparator object is typically
"less<TYPE>", which causes the data to be sorted in ascending order. Each object in a set
has a unique value, as duplicate objects are not allowed. A multiset is similar to a set,
except that a multiset can contain objects with duplicate values.
The following function declares a set of ints, fills it with 10 random values, then prints
them:
void somefunct()
{
INTSET mySet; // declare a set of ints
INTSET::iterator mySetPtr; // and an iterator for
the set
int tmpVal;
Output of somefunct:
A map holds a set of ordered key/value pairs. The pairs are ordered by key, based upon
the user-defined comparator object (3rd template parameter). A map defines a one-to-
one relationship, allowing only one value to be associated with a particular key; a
multimap defines a one-to-many relationship, allowing many values to be associated with
a particular key.
The following declares a map of ints to strings, fills it with 10 key/value pairs and prints
them:
Output of somefunct:
(0, Zero)
(1, One)
(2, Two)
(3, Three)
(4, Four)
(5, Five)
(6, Six)
(7, Seven)
(8, Eight)
(9, Nine)
7. Iterators
Iterators are generalized pointers that may be used to traverse the contents of a sequence
(for example, an STL container or a C++ array).
• Iterators provide data access for both reading and writing data in a sequence.
There are five categories of iterators. With the exception of input and output iterators, the
relationship between each category of iterator is hierarchical: each iterator inherits the
characteristics and behavior of the previous type, as Table 4 illustrates:
In classical C++ terms, input and output iterator classes are base classes, the forward
iterator class is doubly derived from both the input and output iterator classes, the
bidirectional iterator class is derived from the forward iterator class, and the random
access iterator class is derived from the bidirectional iterator class. This hierarchy implies
the following:
• An algorithm that requires only input or output iterators can also be used with
forward, bidirectional, or random access iterators.
• An algorithm that can be used with forward iterators can also be used with
bidirectional or random access iterators.
• An algorithm that can be used with bidirectional iterators can also be used with
random access iterators.
It should also be noted that regular C++ pointers fit the characteristics of a random access
iterator (and in fact can be used as a random access iterator for STL operations that
support random access iterators).
Different iterator types are required to have a minimum set of interface functions defined,
which conform to the behaviors described below. For the following, the value type T is
understood to be the data type of the underlying container that the iterator is interfacing
with (for example, for a vector<int, allocator<int> >, T = int).
A class or built-in data type X can be used as an input iterator for the value type T if and
only if the following expressions are defined for X and meet the behavioral requirements
stated below. For Table 5, assume a and b are values of type X, r is a reference of type X,
and t is a value of type T.
A class or built-in data type X can be used as an output iterator for the value type T if and
only if the following expressions are defined for X and meet the behavioral requirements
stated below. For Table 6, assume a and b are values of type X, r is a reference of type X,
and t is a value of type T.
A class or built-in data type X can be used as a forward iterator for the value type T if and
only if the following expressions are defined for X, and meet the behavioral requirements
stated below. For Table 7, assume a and b are values of type X, t is a value of type T, and
r and s are references of type X.
A class or built-in data type X can be used as a bidirectional iterator for the value type T
if and only if X conforms to the requirements of a forward iterator and defines the
following expressions, which meet the behavioral requirements stated below. For Table 8,
assume r and s are references of type X.
A class or built-in data type X can be used as a random access iterator for the value type
T if and only if X conforms to the requirements of a bidirectional iterator and defines the
following expressions, which meet the behavioral requirements stated below. For Table 9,
assume a and b are values of type X, r is a reference of type X, and n is an int.
The description of each STL container class includes the category of iterator types they
provide. Table 10 lists the various STL containers and the iterators associated with each:
It is not necessary to remember which type of iterator works with which container. Each
container, C<T>, supplies typedefs for iterators:
• iterator (mutable)
• const_iterator (nonmutable)
The following example illustrates how to declare an iterator for a vector of ints and use
that iterator to display the values:
#include <vector>
#include <iostream>
typedef vector<int, allocator<int> > INTVECT;
void main()
{
INTVECT myVector(5); // declare a vector of 5 ints
INTVECT::iterator myIter; // declare an iterator for the vector
for(int iv = 0; iv < 5; iv++)
myVector[iv] = iv; // fill the vector with values
for(myIter = myVector.begin(); myIter != myVector.end(); myIter++)
cout << *myIter << “, “;
cout << endl;
}
Output:
0, 1, 2, 3, 4,
Note that the termination condition for the "for loop" was “myIter != myVector.end()”
instead of “myIter < myVector.end()”. In the above example, the < operator would have
worked because the iterator supplied by a vector is a random access iterator. If our
container had been a list, the < operator would not have worked, as the < operator is not
defined for the bidirectional iterator that list supplies. The moral of the story is that in
such a situation, using != will give the same result and you don’t have to remember
which kind of iterator a particular container is supplying.
One of the reasons input and output iterators are defined separately is so that they can be
associated with I/O streams.
Note Books Online says that istream_iterator takes two template parameters,
Value_Type and Distance_Type, and is derived from input_iterator<Value_Type,
Distance_Type>. The classes were modified to the structure stated above for Visual C++
4.2 to overcome some compiler limitations. A future version of Visual C++ will return to
the structure and hierarchy reflected in the Books Online. The STL is an emerging
standard and will undoubtedly be changed again in the future. In order to minimize the
impact these types of changes will have on existing code, the use of typedefs is highly
recommended when declaring a particular instantiation of any STL component.
The following fills a vector of strings from an input stream using the copy algorithm in
conjunction with an istream_iterator:
See section 7.6.1 for more information on the back inserter class.
The following is the sample from the istream_iterator section with a new addition. Now,
the program prints the strings it has read to stdout, each on a new line. It accomplishes
this by again calling the copy algorithm, this time in conjunction with the string
container, and sends its output to an ostream_iterator object associated with cout:
An adapter in STL is a wrapper class that takes an existing class and provides it with a
new interface. There are two adapters provided by the STL for iterators: reverse iterators
and insert iterators.
Reverse iterator adapters transform their iterators to traverse a collection from back to
front. There are two adapters supplied by the STL: reverse_bidirectional_iterator,
which transforms bidirectional iterators, and reverse_iterator, which transforms random
access iterators. Each container, C<T>, supplies typedefs for reverse iterators:
• reverse_iterator (mutable)
• const_reverse_iterator (nonmutable)
The following example illustrates how to declare a reverse iterator for a vector of ints and
use that iterator to display the values in reverse order:
#include <vector>
#include <iostream>
typedef vector<int, allocator<int> > INTVECT;
void main()
{
INTVECT myVector(5); // declare a vector of 5 ints
// declare a reverse iterator for the vector
INTVECT::reverse_iterator myIter;
for(int iv = 0; iv < 5; iv++)
myVector[iv] = iv; // fill the vector with values
for(myIter = myVector.rbegin(); myIter != myVector.rend();
myIter++)
cout << *myIter << “, “;
cout << endl;
}
Output:
4, 3, 2, 1, 0,
Note the use of rbegin and rend in the above example. Just as each type of STL
container supplies begin and end member functions (which return regular iterators), each
also supplies rbegin and rend member functions (which return reverse iterators).
When reverse iterators are passed to a generic algorithm, they make the algorithm work
in reverse. Consider the sort algorithm:
sort(myVector.begin(), myVector.end());
sort(myVector.rbegin(), myVector.rend());
Sorts the contents into ascending order as seen from back to front, which results in the
contents being sorted into descending order.
Insert iterators put an algorithm into insert mode. The most useful effect of this is that
insert iterators use insert operations (which expand allocated memory as needed) instead
of assignment operations (which assume the space is available) to add objects to a target
container. This is done via a redefinition of operator*, so that *i = … calls one of the
container’s insert functions instead of operator=. Consider the following use of the copy
algorithm to copy the objects from a deque to a vector:
The call to copy above will cause a run-time error (probably a GPF) when *(v1.begin())
= *(d1.begin()) is called, because v1 does not have any memory allocated for itself.
Replacing v1.begin() with an insert iterator, such as back_inserter will solve the
problem as follows:
As noted above, back_inserter iterators call the push_back method of the container
instead of operator= when the iterator’s operator* method is invoked as an l-value. This
means that back_inserter iterators can only be used with containers that support the
push_back method (vector, deque, list). The following illustrates a declaration of a
back_inserter iterator to be associated with a vector:
Because front_inserter iterators call the push_front method of the container instead of
operator= when the iterator’s operator* method is invoked as an l-value, front_inserter
iterators can only be used with containers that support the push_front method (deque,
list). The following illustrates a declaration of a front_inserter iterator to be associated
with a list:
Inserter iterators call the insert method of the container instead of operator= when the
iterator’s operator* method is invoked as an l-value. This means that inserter iterators
can be used with all the STL containers, even the sorted associative containers, as they all
support an insert method. The following illustrates a declaration of an inserter iterator to
be associated with a set that inserts its objects beginning at the second item in the set.
8. Container Adapters
An adapter in STL is a wrapper class that takes an existing class and provides it with a
new interface. There are three adapters provided by the STL for containers: stack, queue,
and priority_queue.
8.1 Stack
A stack adapts any STL container that supports the push_back and pop_back member
functions. It implements a container that performs as stack (Last In, First Out). A stack
may be used to adapt the behavior of a vector, deque or list (as all three support
push_back and pop_back). The deque is the most commonly used container with a
stack.
Note In most implementations of the STL, deque is the default value for the second
template parameter of a stack (the second template parameter specifies the stored
container type). In Visual C++ 4.2, the default argument is not defined due to compiler
limitations.
The following declares a stack of ints, pushes nine values onto the stack, and then pops
each one after printing it:
typedef allocator<int> IALLOC;
typedef deque<int, IALLOC> IDQ;
typedef stack<int, IDQ, IALLOC> ISTACK;
void somefunct(void)
{
ISTACK MyStack;
for(int i = 1; i < 10; i++)
MyStack.push(i);
while(MyStack.size()){
cout << MyStack.top() << ", ";
MyStack.pop();
}
cout << endl;
}
Output:
9, 8, 7, 6, 5, 4, 3, 2, 1,
8.2 Queue
A queue adapts any STL container that supports the push_back and pop_front member
functions. It implements a container that performs as a queue (First In First Out). A
queue may be used to adapt the behavior of a deque or list (as both support push_back
and pop_front). The deque is the most commonly used container with a queue.
Note In most implementations of the STL, deque is the default value for the second
template parameter of a queue (the second template parameter specifies the stored
container type). In Visual C++ version 4.2, the default argument is not defined due to
compiler limitations.
The following declares a queue of ints, pushes nine values onto the queue, and then pops
each one after printing it:
Output:
1, 2, 3, 4, 5, 6, 7, 8, 9,
8.3 Priority_Queue
A priority_queue adapts any STL container that has a random access iterator to maintain
a sorted collections of items. A priority_queue may be used to adapt the behavior of a
vector or a deque (as both are associated with a random access iterator and support
operator[]). The vector is the most commonly used container with a priority_queue.
Note In most implementations of the STL, vector is the default value for the second
template parameter of a priority_queue (the second template parameter specifies the
stored container type). In Visual C++ 4.2, the default argument is not defined due to
compiler limitations.
The third template parameter allows you to specify the comparator used to sort the items.
The following declares a priority_queue of ints, fills it with 10 random values and prints
them in sorted order:
Output:
9, 8, 8, 7, 4, 4, 2, 1, 0,
• See APPENDIX B for the priority_queue class definition
How often have C++ programmers wished they could add two strings using an obvious
syntax like s1 + s2? Or add characters to a string using a syntax like s1 + “Hi”? Even
Microsoft Basic allows that syntax.
The Standard C++ Library provides C++ programmers with a powerful string class. The
string class is based on the basic_string class template.
Standard C++ declares two type definitions, string and wstring, based on basic_string:
The C++ string class is very easy to use. Table 11 describes all the member functions in
brief and the sample in the following section demonstrates the C++ string class.
9.2 Example
The following sample converts a word to Pig Latin. To convert a word to Pig Latin, take
the first character of a word, stick it at the end of the word and add the characters "ay" to
the end of the word. For example, Pig Latin(“hello”) = ellohay.
//piglatin.cpp
#include <string>
#include <iostream>
//convert a string to piglatin
string piglatin(const string& s)
{
string s1 ;
string s2(" .,;:?") ; //word separators
//word boundary markers
size_t start, end, next, p0 ;
int done = 0 ;
start = end = next = 0 ;
while (!done)
{
// Find start of word.
start = s.find_first_not_of(s2, next) ;
// Find end of word.
// Check for end of string.
p0 = s.find_first_of(s2, start) ;
end = (p0 >= s.length()) ? s.length() : p0 - 1 ;
// Copy all the word separators.
s1 = s1 + s.substr(next, start - next) ;
// Convert word to piglatin.
s1 = s1 + s.substr(start + 1, end - start) + s[start] + "ay" ;
next = end + 1;
// Check for end of string.
if( next >= s.length())
done = 1 ;
}
return s1 ;
}
void main()
{
string s("she sells sea shells by the sea shore") ;
cout << "s = " << s << endl ;
cout << "\npiglatin(s) = " << piglatin(s) << "\n"<< endl;
}
Output:
10.2 Introduction
class Matrix
{
public:
Matrix(int, int) ;
//…
int operator(int, int) const ;
private:
Array<int> m_matrix ;
int m_row ;
int m_col ;
} ;
int Matrix::operator(int r, int c) const
{
if ( r > 0 && r <= m_row && c > 0 && c <= m_col)
return m_matrix[r, c] ;
else
return 0 ;
}
Matrix m(10, 10) ;
//….
int element = m(5, 5) ;
Function objects also have the advantage of the fact that () is the only operator that can
take an arbitrary number of arguments. Ever felt the need to create a new function from
existing function(s)? C++ does not allow that. How about using function objects? It is
important to note:
The Standard Template Library provides function objects for standard math operations
such as addition, subtraction, multiplication, and division. STL also provides function
objects for unary operations, logical operations, bitwise operations, and comparison
operations. Table 12 lists all the function objects provided by STL. The function objects
have been defined in the header file <functional>.
divides logical_and
equal_to logical_not
greater logical_or
greater_equal minus
less modulus
less_equal negate
plus not_equal_to
times
These function objects can be used with STL algorithms to change the default behavior of
the STL algorithms. Consider the STL algorithm sort. By default, sort sorts the elements
of a sequence in ascending order. To sort the elements in a descending order use the STL
function object greater<T> as demonstrated in the following example:
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
void main()
{
typedef vector<int, allocator<int> > VECTOR_INT ;
typedef ostream_iterator<int, char, char_traits<char> > OUTIT ;
int a[10] = {30, 56, 79, 80, 45, 10, 4, 125, 67, 80} ;
VECTOR_INT v1(a, a + 10) ;
OUTIT out(cout, ", ") ;
cout << "v1 before sort(first, last)" << endl ;
copy(v1.begin(), v1.end(), out) ;
cout << endl ;
// using default sort algorithm, sorts elements in ascending
order
sort(v1.begin(), v1.end()) ;
cout << "v1 after sort(first, last)" << endl ;
copy(v1.begin(), v1.end(), out) ;
cout << endl ;
random_shuffle(v1.begin(), v1.end()) ;
cout << "v1 before sort(first, last, using STL function object)"
<< endl ;
copy(v1.begin(), v1.end(), out) ;
cout << endl ;
//customizing sort algorithm, to sort elements in descending
order
//using a function object.
sort(v1.begin(), v1.end(), greater<int>()) ;
cout << "v1 after sort(first, last, using STL function-object)"
<< endl ;
copy(v1.begin(), v1.end(), out) ;
cout << endl ;
}
Build the above sample and see the output. We recommend stepping through the code in
the debugger to see what is happening under the covers.
STL function objects can also be used in C++ programs directly. For example:
Function adapters help us construct a wider variety of function objects using existing
function objects. Using function adapters is often easier than directly constructing a new
function object type with a struct or class definition.
STL provides three categories of function adapters: negators, binders, and adapters for
pointer to functions.
10.4.1 Binders
Binders are function adapters that convert binary function objects into unary function
objects by binding an argument to some particular value.
STL provides two template functions, bind1st and bind2nd, to create binder function
objects. The functions bind1st and bind2nd each take as arguments a binary function
object f and a value x. As might be surmised, bind1st returns a function object of type
binder1st<Operation>, and bind2nd returns a function object of type
binder2nd<Operation>. Here are the function prototypes for the bind1st and bind2nd
functions:
So now it is easier to understand: f is a binary function object that compares two integers,
x and y; b is a unary function object that sets the second argument of f to the value 200;
and result is therefore (i > 200).
int a1[1000] ;
//code to initialize a1 …
int* where = find_if(a1, a1+1000, bind2nd(greater<int>(), 200));
The find_if function finds the first element in array a1, which is > 200. In this case it is
not possible to use the expression "(greater<int>())(i, 200)" as the third argument to
find_if. How does one determine the value of i? The find_if function will supply the
value i to the function object greater and the unary function object created by bind2nd.
Also, bind2nd binds the value 200 to the second argument of function object greater.
This notation makes it possible to work with the entire container at once, instead of
writing loops to deal with individual elements. It makes the source code smaller, more
reliable, and easier to read.
bind1st converts the binary function object f into a unary function object by binding the
argument x to the first argument of function object f.
bind2nd converts the binary function object f into a unary function object by binding the
argument x to the second argument of function object f.
10.4.2 Negators
The two template functions, not1 and not2, create negator function objects. The function
not1 takes a unary function object f as its argument and returns a function object of type
unary_negate<Operation>. The function not2 takes a binary function object f as its
argument and returns a function object of type binary_negate<Operation>. Here are the
function prototypes for the not1 and not2 functions:
int a1[1000] ;
//code to initialize a1 …
int* where = find_if(a1, a1+1000, not1(bind2nd(greater<int>(), 200)));
In this case, find_if finds the first element in array a1 that is not > 200 (that is, <= 200).
The function bind2nd creates a unary function object which returns the result of the
comparison i > 200. The function not1 takes the unary function object as an argument
and creates another function object. This function object merely negates the results of the
comparison i > 200. Here is an example of using the not2 function:
In this case, sort will sort elements in ascending order. The not2 function negates the
results of the function object greater.
Adapters for pointers to functions convert existing binary or unary functions to function
objects. Adapters for pointers to functions allow the programmer to utilize the existing
code to extend the library, apply idioms unique to your application, and so forth.
STL provides two versions of the template function ptr_fun to create pointer-to-function
function objects. The first version of ptr_fun takes a unary function f as its argument and
returns a function object of type pointer_to_unary_function<Arg, Result>. The second
version of ptr_fun takes a binary function f as its argument and returns a function object
of type pointer_to_binary_function<Arg1, Arg2, Result>. Here are the function
prototypes for the ptr_fun functions:
template<class Arg, class Result> inline
pointer_to_unary_function<Arg, Result> ptr_fun(Result (*F)(Arg))
Let us look at an example and try to understand what pointers to functions do:
In this example, function ptr_fun converts the C++ unary function Rand into a
pointer_to_binary_function function object. Build the above sample and examine the
output. We recommend stepping through the code in the debugger to see what is
happening under the covers!!
This chapter will introduce the STL algorithm fundamentals and present some examples.
Remembering some basic rules will help you to understand the algorithms and how to use
them.
• The STL algorithms are user programmable. What this means is that you can
modify the default behavior of an algorithm to suit your needs. For example, the
sort algorithm:
• sort(first, last) ; //sorts elements of a sequence
• //in ascending order by default.
In this case the STL algorithm assumes an operator == or operator < exists, and
uses it to compare elements.
• The algorithm will increment an internal iterator with the ++ operator until
it equals last. The element pointed to by last will not be processed by the
algorithm.
• STL Algorithms do not perform range or validity checking on the iterator or
pointer values. Many algorithms work with two sequences. For example, the copy
algorithm takes three parameters, as follows:
• //Copy contents of sequence1 to sequence2.
• // First1 and last1 mark start and end of
• // Sequence1, respectively. First2 marks the start
• // of sequence2.
• copy(first1, last1, first2) ;
• ·If sequence2 is shorter than sequence1, copy will merrily continue writing
into unconnected areas of memory.
• Some STL algorithms also creates an in-place version and a copying version. For
example:
• // In-place version places the results back in
• //the same container.
• reverse(first, last) ;
• // Copying version places the results in
• //in another sequence and does not modify the
• //original sequence.
• reverse_copy(first1, last1, first1) ;
• The STL generic algorithms can be divided into the following four main
categories:
4.Finally there
is a small collection of Generalized Numeric Algorithms.
• The STL algorithms are defined in the three header files: <algorithm>,
<functional>, <numeric>.
Let us look at some examples now. These examples demonstrate how to use the
algorithms and explain different concepts.
11.2 reverse and reverse_copy
Description: Reverse the order of items in a sequence specified by the range [first, last).
Signature:
Signature:
The following example demonstrates how to use the reverse and reverse_copy
functions.
//reverse.cpp
#pragma warning(disable:4786)
#include <iostream>
#include <algorithm>
#include <list>
#include <string>
void main()
{
typedef list<string, allocator<string> > STRINGLIST ;
typedef STRINGLIST::iterator STRINGLIST_ITERATOR ;
typedef ostream_iterator<string, char,
char_traits<char> > OS_ITERATOR ;
int i ;
STRINGLIST_ITERATOR iT, iT2 ;
// print contents of Names1
cout << "Names1 array: " << endl ;
for(i = 0; i < 6; i++)
cout << Names1[i] << ", " ;
cout << "\n" << endl ;
11.3 sort
Description: Sort a sequence. Sort all elements in the range [first, last) into ascending
order. The first version uses operator< to compare elements while the second version uses
a function/function object.
Signature:
The following example demonstrates how to use the nonpredicate and predicate version
of the sort function.
//sort.cpp
//Using the generic sort algorithm
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
class compObj
{
public:
bool operator()(int x, int y)
{
return x > y ;
}
} ;
void main()
{
typedef vector<int, allocator<int> > VECTOR_INT ;
typedef ostream_iterator<int, char, char_traits<char> > OUTIT ;
int a[10] = {30, 56, 79, 80, 45, 10, 4, 125, 67, 80} ;
VECTOR_INT v1(a, a + 10) ;
OUTIT out(cout, ". ") ;
random_shuffle(v1.begin(), v1.end()) ;
random_shuffle(v1.begin(), v1.end()) ;
random_shuffle(v1.begin(), v1.end()) ;
The language support section of the Standard C++ Library provides common type
definitions used throughout the library, characteristics of pre-defined types, functions
supporting start and termination of C++ programs, support for dynamic memory
allocation, support for dynamic type identification, support for exception processing, and
other run-time support.
This header file basically includes stddef.h. There are two macros, NULL and offsetof,
and two types, ptrdiff_t and size_t, specifically listed in this section of the standard.
To determine the distance (or the number of elements) between two elements you can use
the distance() function. If you pass it an iterator pointing to the first element and one
pointing to the third element, it will return a 2.
The distance function is in the utility header file and it takes two iterators as parameters
and returns a number of type difference_type. Difference_type maps is an int. The
sequence is:
Note With Visual C++ 4.2 the online help states the difference function takes 3
parameters and returns void. For example:
#include <iostream>
#include <vector>
#include <iterator>
#include <string>
#pragma warning (disable:4786)
typedef vector<string, allocator<string> > VTRLIST;
void main() {
VTRLIST Vector;
VTRLIST::iterator iVector;
VTRLIST::difference_type dTheDiff;
Vector.push_back("A1");
Vector.push_back("B2");
Vector.push_back("C3");
Vector.push_back("D4");
Vector.push_back("E5");
Vector.push_back("F6");
Vector.push_back("G7");
// Print out the list.
iVector=Vector.begin();
cout << "The list is: ";
for (int i = 0; i < 7 ; i++, iVector++)
cout << *iVector << " ";
#include <iostream>
#include <limits>
void main() {
cout << " 1 The minimum value for char is " <<
(int)numeric_limits<char>::min() << endl;
cout << " 2 The minimum value for int is " <<
numeric_limits<int>::min() << endl;
cout << " 3 The maximum value for char is " <<
(int)numeric_limits<char>::max() << endl;
cout << " 4 The maximum value for int is " <<
numeric_limits<int>::max() << endl;
cout << " 5 The number of bits to represent a char is " <<
numeric_limits<char>::digits << endl;
cout << " 6 The number of bits to represent an int is " <<
numeric_limits<int>::digits << endl;
cout <<" 7 The number of digits representble in base 10 for float
is"
<< numeric_limits<float>::digits10 << endl;
cout << " 8 Is a char signed? " <<
numeric_limits<char>::is_signed << endl;
cout << " 9 Is an unsigned integer signed? " <<
numeric_limits<unsigned int>::is_signed << endl;
cout << "10 Is a integer an integer? " <<
numeric_limits<int>::is_integer << endl;
cout << "11 Is a float an integer? " <<
numeric_limits<float>::is_integer << endl;
cout << "12 Is a integer exact? " <<
numeric_limits<int>::is_exact << endl;
cout << "13 Is a float exact? " <<
numeric_limits<float>::is_exact << endl;
cout << "14 The radix for float is " <<
numeric_limits<float>::radix << endl;
cout << "15 The epsilon for float is " <<
numeric_limits<float>::epsilon() << endl;
cout << "16 The round error for float is " <<
numeric_limits<float>::round_error() << endl;
cout << "17 The minimum exponent for float is " <<
numeric_limits<float>::min_exponent << endl;
cout << "18 The minimum exponent in base 10 " <<
numeric_limits<float>::min_exponent10 << endl;
cout << "19 The maximum exponent is " <<
numeric_limits<float>::max_exponent << endl;
cout << "20 The maximum exponent in base 10 " <<
numeric_limits<float>::max_exponent10 << endl;
cout << "21 Can float represent positive infinity? " <<
numeric_limits<float>::has_infinity << endl;
cout << "22 Can double represent positive infinity? " <<
numeric_limits<double>::has_infinity << endl;
cout << "23 Can int represent positive infinity? " <<
numeric_limits<int>::has_infinity << endl;
cout << "24 Can float represent a NaN? " <<
numeric_limits<float>::has_quiet_NaN << endl;
cout << "25 Can float represent a signaling NaN? " <<
numeric_limits<float>::has_signaling_NaN << endl;
cout << "26 Does float allow denormalized values? " <<
numeric_limits<float>::has_denorm << endl;
cout << "27 Does float detect denormalization loss? " <<
numeric_limits<float>::has_denorm_loss << endl;
cout << "28 Representation of positive infinity for float " <<
numeric_limits<float>::infinity() << endl;
cout << "29 Representation of quiet NaN for float " <<
numeric_limits<float>::quiet_NaN() << endl;
cout << "30 Minimum denormalized number for float " <<
numeric_limits<float>::denorm_min() << endl;
cout << "31 Minimum positive denormalized value for float " <<
numeric_limits<float>::denorm_min() << endl;
cout << "32 Does float adhere to IEC 559 standard? " <<
numeric_limits<float>::is_iec559 << endl;
cout << "33 Is float bounded? " <<
numeric_limits<float>::is_bounded << endl;
cout << "34 Is float modulo? " <<
numeric_limits<float>::is_modulo << endl;
cout << "35 Is int modulo? " <<
numeric_limits<float>::is_modulo << endl;
cout << "36 Is trapping implemented for float? " <<
numeric_limits<float>::traps << endl;
cout << "37 Is tinyness detected before rounding? " <<
numeric_limits<float>::tinyness_before << endl;
cout << "38 What is the rounding style for float? " <<
(int)numeric_limits<float>::round_style << endl;
cout << "39 What is the rounding style for int? " <<
(int)numeric_limits<int>::round_style << endl;
}
Output:
Additional values defined from the <climits> and <cfloat> header files which include
<limits.h> and float.h, respectively, are:
Note The LDBLxxx constants are not listed in the online help for Visual C++ 4.2 but
they are defined in <float.h>
There are two additional constants defined in the Visual C++ 4.2 implementation that are
not a part of the Standard C++ Library, they are:
_DBL_RADIX
_DBL_ROUNDS
See the online help with Visual C++ 4.2 for descriptions of these constants.
The cstdlib header file includes the C header file <cstdlib.h>. Table 14 lists the functions
specified.
Function Description
void abort( void ); Aborts the current process and returns an error
code.
int atexit( void ( __cdecl *func ) Processes the specified function at exit.
( void ) );
void exit( int status ); Terminate the calling process after cleanup
(exit) or immediately (_exit).
The main thing to note is that there is support for the operator new either returning NULL
or throwing an exception on failure.
The class nothrow{} is used as a function parameter to indicate that the function should
never throw an exception.
The online help for the operator new in the Visual C++ 4.2 Standard C++ Library
Reference is pretty good. Either query on 'operator new' or look in the help for the
<new> header file.
In the above prototypes, don't let the throw(), throw you. Visual C++ 4.2 does not
implement these exception specifications. This is noted in the online help.
Microsoft C++ does not support the function throw signature mechanism, as described in
section 15.5 of the ANSI C++ draft.
Microsoft C++ does not support the function exception specification mechanism, as
described in section 15.4 of the ANSI C++ draft.
An exception specification specifies the type of exceptions a function can throw, for
example:
will throw a bad_alloc exception if the memory allocation fails. Or if you define a
new_handler function via set_new_handler, the new handler function will be called
instead.
These operators:
In the following sample, the first operator new will attempt to allocate memory and, if it
fails, will throw an exception. The second operator new accepts a second parameter of
type nothrow. This parameter indicates that if the allocation fails, it should return NULL
and not throw an exception. The third operator, new, will allocate memory for an array of
that type and, if it fails, throw an exception.
#include <new>
#include <iostream>
class BigClass {
public:
BigClass() {};
~BigClass(){}
double BigArray[99999999];
};
void main() {
try {
BigClass * p = new BigClass;
}
catch( bad_alloc a) {
const char * temp = a.what();
cout << temp << endl;
cout << "Threw a bad_alloc exception" << endl;
}
BigClass * q = new(nothrow) BigClass;
if ( q == NULL )
cout << "Returned a NULL pointer" << endl;
try {
BigClass * r = new BigClass[3];
}
catch( bad_alloc a) {
const char * temp = a.what();
cout << temp << endl;
cout << "Threw a bad_alloc exception" << endl;
}
}
Program Output is:
bad allocation
Threw a bad_alloc exception
Returned a NULL pointer
bad allocation
Threw a bad_alloc exception
Note that the above example uses the what() function to print out the type of exception.
This function is a part of the exception class. The value returned by what() is
implementation defined.
An important thing to note is that code which previously returned a NULL when a call to
new failed will instead throw an exception if you use the standard C++ header files. This
means that if you modify your code to include <new> then you also need to modify your
code to check for an exception rather than checking to see if new returned NULL.
Intermixing old header files with the new standard C++ header files can cause multiple
problems with the new operator. For example, if the following code:
class BigClass {
public:
BigClass() {};
~BigClass(){}
double BigArray[99999999];
};
void main() {
BigClass * q = new BigClass;
if ( q == NULL )
cout << "Returned a NULL pointer" << endl;
}
#include <iostream.h>
// No Errors.
#include <iostream.h>
#include <new>
// No errors - returns a NULL.
#include <new>
#include <iostream.h>
// No errors - returns a NULL.
#include <new>
#include <iostream>
// Throws an exception instead of returning NULL.
#include <iostream>
// Throws an exception instead of returning NULL.
If you are using the newer forms of the operator new such as:
class BigClass {
public:
BigClass() {};
~BigClass(){}
double BigArray[99999999];
};
void main() {
try {
BigClass * p = new BigClass;
}
catch( bad_alloc a) {
const char * temp = a.what();
cout << temp << endl;
cout << "Threw a bad_alloc exception" << endl;
}
BigClass * q = new(nothrow) BigClass;
if ( q == NULL )
cout << "Returned a NULL pointer" << endl;
}
and include the following header files, you will get the noted results.
#include <new>
#include <iostream>
// No Errors.
#include <iostream>
#include <new>
// No Errors.
#include <iostream>
// No Errors.
#include <new>
//C:\MSDEV\Projects\defcon\Text5.cpp(40) : error C2065: 'cout' :
undeclared identifier
//C:\MSDEV\Projects\defcon\Text5.cpp(40) : error C2297: '<<' : bad
right operand
//C:\MSDEV\Projects\defcon\Text5.cpp(40) : error C2065: 'endl' :
undeclared identifier
//C:\MSDEV\Projects\defcon\Text5.cpp(41) : error C2297: '<<' : bad
right operand
//C:\MSDEV\Projects\defcon\Text5.cpp(45) : error C2297: '<<' : bad
right operand
#include <new>
#include <iostream.h>
// ext5.obj : error LNK2001: unresolved external symbol "void * __cdecl
operator new(unsigned int,struct nothrow_t const
&)"(??2@YAPAXIABUnothrow_t@@@Z)
// Debug/defcon.exe : fatal error LNK1120: 1 unresolved externals
#include <iostream.h>
#include <new>
// Text5.obj : error LNK2001: unresolved external symbol "void *
__cdecl operator new(unsigned int,struct nothrow_t const
&)"(??2@YAPAXIABUnothrow_t@@@Z)
// Debug/defcon.exe : fatal error LNK1120: 1 unresolved external
#include <iostream.h>
//C:\MSDEV\Projects\defcon\Text5.cpp(47) : error C2061: syntax error :
identifier 'bad_alloc'
//C:\MSDEV\Projects\defcon\Text5.cpp(47) : error C2310: catch handlers
must specify one type
//C:\MSDEV\Projects\defcon\Text5.cpp(48) : error C2065: 'a' :
undeclared identifier
//C:\MSDEV\Projects\defcon\Text5.cpp(48) : error C2228: left of '.what'
must hav class/struct/union type
//C:\MSDEV\Projects\defcon\Text5.cpp(52) : error C2317: 'try' block
starting on line '44' has no catch handlers
//C:\MSDEV\Projects\defcon\Text5.cpp(52) : error C2065: 'nothrow' :
undeclared identifier
//C:\MSDEV\Projects\defcon\Text5.cpp(52) : error C2660: 'new' :
function does not take 2 parameters
The <typeinfo> header defines a type associated with the type information generated by
the implementation (type_info). It also defines two types for reporting dynamic type
identification errors (bad_cast and bad_typeid).
The type_info class is defined with a raw_name member in the help and header files (in
both Visual C++ and the library). However, in the current version of the C++ Library
Standard, there is no raw_name member. The raw_name member function returns a
const char* to a null-terminated string representing the decorated name of the object
type.
class type_info {
public:
virtual ~type_info();
int operator==(const type_info& rhs) const;
int operator!=(const type_info& rhs) const;
int before(const type_info& rhs) const;
const char* name() const;
const char* raw_name() const;
private:
...
};
The exception class defines the base class for the types of objects thrown as exceptions
by the C++ Standard Library components. The exception header file defines the
exception class that is the base class for all exceptions thrown by the C++ Standard
Library. The following code would catch any exception thrown by classes and functions
in the Standard C++ Library:
try {
// code
}
catch ( const exception &ex)
{
cout << "exception: " << ex.what();
}
class exception {
public:
exception() throw();
exception(const exception& rhs) throw();
exception& operator=(const exception& rhs) throw();
virtual ~exception() throw();
virtual const char *what() const throw();
private:
…
};
See Exception Handling and Standard C++ Library Diagnostics for further details.
With Visual C++ 4.2, each of these headers files includes the corresponding C header file,
stdarg.h, setjmp.h, time.h, signal.h, and stdlib.h. Macros, types, and functions listed for
each of these in the Standard C++ Library are as follows:
cstdarg
Macros: va_arg va_end va_start
Types: va_list
csetjmp
Macro: setjmp
Types: jmp_buf
Function: longjmp
ctime
Macros: CLOCKS_PER_SEC
Types: clock_t
Functions: clock
csignal
Macros: SIGABRT SIGILL SIGSEGV SIG_DFL
SIG_IGN SIGFPE SIGINT SIGTERM SIG_ERR
Types: sig_atomic_t
Functions: raise signal
cstdlib
Functions: getenv system
There was always a need to write robust and powerful programs that are resistant to run
time errors, logic errors, and all other unexpected events. Exception handling is a
relatively new and powerful tool that can be used for better and safer programming. As in
many other areas, a good intention can lead to disastrous results. So, if you are not sure
why and how to use exception handling, you are better off not using it at all.
C++ exception handling uses three statements (try, catch, and throw) added to the C++
language. With C++ exception handling, your program can propagate unexpected events
to a higher execution context that is better able to recover from such abnormal events.
These exceptions are handled by code outside the normal flow of control. The Microsoft
C++ compiler implements the C++ exception-handling model based on the ISO
WG21/ANSI X3J16 working papers toward the evolving standard for C++.
Note Structured exception handling works with Microsoft Win32® for both C and C++
source files. However, it is not specifically designed for C++. Your code is more portable
when using C++ exception handling and is also more flexible because it can handle
exceptions of any type. For C++ programs, it is recommended that you use the new C++
exception-handling mechanism (try, catch, and throw statements).
The major difference between structured exception handling and C++ exception handling
is that the C++ exception-handling model uses any data type, while the C structured
exception-handling model uses type; unsigned int. That is, C exceptions are identified by
an unsigned integer value, whereas C++ exceptions are identified by data type. When an
exception is raised in C, each possible handler executes a filter, which examines the C
exception context and determines whether to accept the exception, pass it to some other
handler, or ignore it. When an exception is thrown in C++, it may be of any type.
************************************************************/
#include <stdio.h>
int *p = NULL; // pointer used to generate an AV
class CMyObject {
public:
~CMyObject () {
printf ("Here is the destructor for CMyObject\n");
}
};
void function1()
{
CMyObject ob;
Synchronous exceptions are objects thrown in C++ with a throw() statement. The
synchronous exception-handling model is designed for catching synchronous exceptions
only. The asynchronous exception-handling model is designed to catch synchronous
exceptions and structured exception-handling type exceptions such as access violation
and divides by zero.
The compiler can assume exception can only happen at function calls. This makes it a lot
easier to optimize the code and allows the removal of exception handling tracking code
for local unwindable objects whose scope doesn't span across a function call (or where all
calls are inlined).
13.4.4 _declspec(nothrow)
You can also tune your code by telling the compiler that a particular function never
throws an exception by using _declspec(nothrow) on the function declaration, or by
using the new C++ nothrow specification.
• A goto, break, return, or continue statement can be used to transfer control out
of a try block or handler, but not into one. When this happens, each variable
declared in the try block will be destroyed in the context that directly contains its
declaration.
• A function try block associates a handler seq with the ctor initializer, if present,
and the function body. An exception thrown during the execution of the initializer
expressions in the ctor initializer or during the execution of the function body
transfers control to a handler in a function try block in the same way as an
exception thrown during the execution of a try block transfers control to other
handlers.
• //Example:
• int f(int);
• class C {
• int i;
• double d;
• public:
• C(int, double);
• };
• C::C(int ii, double id)
• try
• i(f(ii)), d(id)
• {
• // Constructor function body
• }
• catch (...)
• {
• // Handles exceptions thrown from the ctor-
initializer
• // and from the constructor function body.
• }
Throwing an exception transfers control to a handler. An object is passed and the type of
that object determines which handlers can catch it.
//Example:
throw "Help!";
can be caught by a handler of some char* type:
try {
// ...
}
catch(const char* p) {
// Handle character string exceptions here.
}
and
class Overflow {
// ...
public:
Overflow(char,double,double);
};
void f(double x)
{
// ...
throw Overflow('+',x,3.45e107);
}
try {
// ...
f(1.2);
// ...
}
catch(Overflow& oo) {
// handle exceptions of type Overflow here
}
The memory for the temporary copy of the exception being thrown is allocated in an
implementation-defined way. The temporary persists as long as there is a handler being
executed for that exception.
A throw expression with no operand rethrows the exception being handled without
copying it. For example, code that must be executed because of an exception, yet cannot
completely handle the exception, can be written as follows:
//Example:
try {
// ...
}
catch (...) { // catch all exceptions
// respond (partially) to exception
throw; // pass the exception to some
// other handler
}
As control passes from a throw point to a handler, destructors are invoked for all
automatic objects constructed since the try block was entered. The automatic objects are
destroyed in the reverse order of the completion of their construction.
An object that is partially constructed will have destructors executed only for its fully
constructed subobjects. If a constructor for an element of an automatic array throw an
exception, only the constructed elements of that array will be destroyed.
The process of calling destructors for automatic objects constructed on the path from a try
block to a throw expression is called stack unwinding.
The exception declaration in a handler describes the type(s) of exceptions that can cause
that handler to be entered. The exception declaration shall not denote an incomplete type.
Types shall not be defined in an exception declaration.
The handlers for a try block are tried in order of appearance. That makes it possible to
write handlers that can never be executed—for example, by placing a handler for a
derived class after a handler for a corresponding base class.
A ... in a handler exception declaration functions similarly to ... in a function parameter
declaration; it specifies a match for any exception. If present, a ... handler shall be the last
handler for its try block.
If no match is found among the handlers for a try block, the search for a matching handler
continues in a dynamically surrounding try block.
An exception is considered handled upon entry to a handler. (Note: the stack will have
been unwound at that point.)
Referring to any nonstatic member or base class of an object in the function try block
handler of a constructor or destructor for that object results in undefined behavior.
The fully constructed base classes and members of an object shall be destroyed before
entering the function try block handler of a constructor or destructor for that object.
The scope and lifetime of the parameters of a function or constructor extend into the
handlers of a function try block.
If the handlers of a function try block contain a jump into the body of a constructor or
destructor, the program is ill-formed.
The exception being handled is rethrown if control reaches the end of a handler of the
function try block of a constructor or destructor. Otherwise, a function returns when
control reaches the end of a handler for the function try block.
When the catch handler specifies a class object, a copy constructor is used to initialize a
temporary object that is bound to the optionally specified name in the exception
declaration for the catch handler. The object shall not have an abstract class type, because
objects of those types shall not be created. That object is destroyed when the handler is
exited, after the destruction of any automatic objects initialized within the handler. The
copy constructor and destructor shall be accessible in the context of the catch handler. If
the copy constructor and destructor are implicitly declared, such a use in the catch
handler causes these functions to be implicitly defined; otherwise, the program shall
provide a definition for these functions. If the use of a temporary object can be eliminated
without changing the meaning of the program (except for execution of constructors and
destructors associated with the use of the temporary object), the optional name can be
bound directly to the temporary (or original) object specified in a throw expression that
causes the catch handler to be executed. The copy constructor and destructor associated
with the object shall be accessible even when the temporary object is eliminated.
When the catch handler specifies a nonconstant object, any changes to the object that are
effected before the handler has exited are changes to the temporary copy for the handler.
These changes will not affect the temporary (or original) object that was initialized by
execution of the throw expression. When the catch handler specifies a reference to a
nonconstant object, any changes to the referenced object are changes to the temporary (or
original) object initialized when the throw expression was executed. These changes will
have effect if that object is rethrown.
exception-specification:
throw ( type-id-listopt )
type-id-list:
type-id
type-id-list , type-id
//Example:
void f() throw(int); // OK
void (*fp)() throw (int); // OK
void g(void pfa() throw(int)); // OK
typedef int (*pf)() throw(int); // Ill-formed
Note Exception specification is optional and the absence of one does not impose
restrictions on the possible function exceptions.
//Example:
struct B {
virtual void f() throw (int, double);
virtual void g();
};
struct D: B {
void f(); // ill-formed
void g() throw (int); // OK
};
The declaration of D::f is ill-formed because it allows all exceptions, whereas B::f allows
only int and double. Similarly, any function or pointer-to-function assigned to, or
initializing, a pointer-to-function shall only allow exceptions that are allowed by the
pointer or function being assigned or initialized.
//Example:
void (*pf1)(); // no exception specification
void (*pf2)() throw(A);
void f()
{
pf1 = pf2; // ok: pf1 is less restrictive
pf2 = pf1; // error: pf2 is more restrictive
}
An exception specification can include the same class more than once and can include
classes related by inheritance even though doing so is redundant. An exception
specification can include identifiers that represent incomplete types. An exception
specification can also include the name of the predefined class bad_exception.
Whenever an exception is thrown and the search for a handler encounters the outermost
block of a function with an exception specification, the unexpected() function is called if
the exception specification does not allow the exception.
class X { };
class Y { };
class Z: public X { };
class W { };
void f() throw (X, Y)
{
int n = 0;
if (n) throw X(); // OK
if (n) throw Z(); // also OK
throw W(); // will call unexpected()
}
The unexpected() function may throw an exception that will satisfy the exception
specification for which it was invoked (in this case, the search for another handler will
continue at the call of the function with this exception specification) or it may call
terminate.
The call to f is well formed even though when called, f may throw exception Y that g does
not allow.
Exception handling must be abandoned for less subtle error handling techniques:
If a function with an exception specification throws an exception that is not listed in the
exception specification, the unexpected() function is called.
The unexpected() function shall not return, but it can throw (or rethrow) an exception. If
it throws a new exception that is allowed by the previously violated exception
specification, the search for another handler will continue at the call of the function
whose exception specification was violated. If it throws or rethrows an exception that the
exception specification does not allow, one of two things can happen. If the exception
specification does not include the name of the predefined exception bad_exception, the
terminate() function is called; otherwise, the thrown exception is replaced by an
implementation-defined object of the type bad_exception and the search for another
handler will continue at the call of the function whose exception specification was
violated.
An exception specification guarantees that only the listed exceptions will be thrown. If
the exception specification includes the name bad_exception, any exception not on the
list may be replaced by bad_exception within the function unexpected().
The following predicate returns true after completing evaluation of the object to be
thrown until the exception declaration in the matching handle completes initialization.
(This includes stack unwinding.)
bool uncaught_exception();
13.11 Exceptions and Access
If the exception declaration in a catch clause has class type and the function in which the
catch clause occurs does not have access to the destructor of that class, the program is ill-
formed.
An object can be thrown if it can be copied and destroyed in the context of the function in
which the throw expression occurs.
The Diagnostics Library contains new components that C++ programs may use to detect
and report error conditions.
The following header files contain components for reporting several kinds of exceptional
conditions, documenting program assertions, and a global variable for error number
codes:
Using a common base class allows the use of one handler for many related exceptions.
For example, a set of exception objects for memory allocation problems could be derived
from the MemoryException base class such as out memory or ZeroAlloc. A single catch
(MemoryException) handler would catch all memory exceptions including new ones.
Virtual functions allow derived exception classes to use internal information that doesn’t
exist in the base class.
The following example demonstrates how to use class hierarchies to define your own
exception classes.
{
ex.DisplayMessage();
}
}
void InitApp()
{
try {
iBuf = new int [szBuf];
cBuf = new char [szBuf];
}
catch (...) {
throw OutOfMemory();
}
}
Exceptions defined within a template class can be specific to each generated class. Given
the following:
A catch block would need to specify the type of vector that it is handling, as follows:
The following example demonstrates how to use exception classes with templates.
You would need to define handlers for each excepted type of vector; otherwise, the types
not listed will be handled by terminate () function. The exception could be defined
outside of the Vector class as a global to all vector types.
Exceptions defined within a class follow the standard access rules. If a class only handles
an exception internally, the exception class should be private or protected. If you want the
exception to be handled externally, make it public or define it outside of the error-
producing class.
The following is an example of how to use exception classes with STL containers.
class ExceptionRange
{
public:
ExceptionRange (size_type _P) {
cout << endl;
cout <<"An attempt was made to access an element out of
range"<<endl;
cout << "Element for index: " << _P << " doesn't exist."
<< endl;
}
};
const_reference operator[](size_type _P) const throw
(ExceptionRange)
{
if ( _P > ((end()-1) - begin()))
{
throw ExceptionRange(_P);
return(*(end()));
}
return (*(begin() + _P));
}
reference operator[](size_type _P) throw (ExceptionRange)
{
if ( _P > ((end()-1) - begin()))
{
throw ExceptionRange(_P);
return(*(end()));
}
return (*(begin() + _P));
}
};
#endif
// VectorMain.cpp
/**************************************************************
// Compile Options /GX
/**************************************************************
This program demonstrates how to use Exception classes with
STL.
MyVector is a derived from Vector template class.
This is just one method to make the use of STL library more safe.
**************************************************************/
#include <iostream>
#include "MyVector.h"
void main()
{
MyVector<int> intVect;
MyVector<int>::iterator intVectPtr;
for(int i = 0; i < 20; i++)
intVect.push_back(i*2);
for(intVectPtr = intVect.begin(); intVectPtr != intVect.end();
intVectPtr++)
cout << *intVectPtr << ", ";
cout <<endl<<endl;
try
{
for (int k = 0; k < 30 ;k++ )
cout << intVect[k] <<", ";
}
catch (MyVector <int>::ExceptionRange)
{
cout <<endl;
cout << "Exception: Vector out of range" << endl;
}
}
Program Output:
0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36,
38,
0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36,
38,
An attempt was made to access an element out of range.
Element for index: 20 doesn't exist.
Exception: Vector out of range.
class exception {
public:
exception() throw();
exception(const exception& rhs) throw();
exception& operator=(const exception& rhs) throw();
virtual ~exception() throw();
virtual const char *what() const throw();
};
The class serves as the base class for all exceptions thrown by certain expressions and by
the Standard C++ Library. The C-string value returned by what() is left unspecified by
the default constructor, but may be defined by the constructors for certain derived classes.
None of the member functions throws any exceptions.
• The Standard C++ Library provides classes to be used to report certain errors in
C++ programs. In the error model reflected in these classes, errors are divided
into two broad categories: logic errors and run-time errors.
• The distinguishing characteristic of logic errors is that they are due to errors in the
internal logic of the program. In theory, they are preventable.
• By contrast, run-time errors are due to events beyond the scope of the program.
They cannot be easily predicted in advance. The header <stdexcept> defines
several types of predefined exceptions for reporting errors in a C++ program.
These exceptions are related via inheritance.
#include <exception>
#include <string>
namespace std {
class logic_error;
class domain_error;
class invalid_argument;
class length_error;
class out_of_range;
class runtime_error;
class range_error;
class overflow_error;
class underflow_error;
}
class logic_error
namespace std {
class logic_error : public exception {
public:
logic_error(const string& what_arg);
};
}
The class LOGIC_ERROR defines the type of objects thrown as exceptions to report
errors that are, presumably, detectable before the program executes, such as violations of
logical preconditions or class invariants.
class domain_error
namespace std {
class domain_error : public logic_error {
public:
domain_error(const string& what_arg);
};
}
The class DOMAIN_ERROR defines the type of objects thrown as exceptions, by the
implementation, to report domain errors.
class length_error
namespace std {
class length_error : public logic_error {
public:
length_error(const string& what_arg);
};
}
The class LENGTH_ERROR defines the type of objects thrown as exceptions to report
an attempt to produce an object whose length exceeds its maximum allowable size.
The class OUT_OF_RANGE defines the type of objects thrown as exceptions to report
an argument value not in its expected range.
out_of_range(const string& what_arg);
Effects:
Constructs an object of class out_of_range.
Postcondition:
what() == what_arg.data().
class runtime_error
namespace std {
class runtime_error : public exception {
public:
runtime_error(const string& what_arg);
};
}
The class RUNTIME_ERROR defines the type of objects thrown as exceptions to report
errors presumably detectable only when the program executes.
class range_error
namespae std {
class range_error : public runtime_error {
public:
range_error(const string& what_arg);
};
}
The class RANGE_ERROR defines the type of objects thrown as exceptions to report
range errors in internal computations.
class overflow_error
namespace std {
class overflow_error : public runtime_error {
public:
overflow_error(const string& what_arg);
};
}
class underflow_error
namespace std {
class underflow_error : public runtime_error {
public:
underflow_error(const string& what_arg);
};
}
14.4.2 Assertions
This provides macros for documenting C++ program assertions, and for disabling the
assertion checks.
Header <cassert>
Type Name(s)
Macro assert
Header <cerrno> :
Type Name(s)
Macros EDOM ERANGE errno
throw float_error(buffer);
return 0;
}
void TestMathErrors(double (*fp) (double), double arg)
{
//Next text
bool caught = false;
//Generate a floating-point error.
try {
double x = fp (arg);
}
catch (exception & ex)
{
cout << ex.what() << endl<<endl;
caught = true;
}
if (!caught)
cout << "didn't catch exception through materr\r\n";
}
int main (void)
{
typedef double (*fp) (double);
//Array to the several functions
fp math_function [] = { &sqrt, &log, &sin, &tan, &acos };
double arg []= { -1.0, 0.0, 1.5e25, 1.5e25, 2 };
TestMathErrors(math_function[n],arg[n]);
return 0;
}
Floating point math error occurred in your program. More details below:
Domain Error: : sqrt(-1,-3.10504e+231) returns -1.#IND
Floating point math error occurred in your program. More details below:
Singularity Error:: log(0,-3.10504e+231) returns -1.#INF
Floating point math error occurred in your program. More details below:
Total loss of significance:: sin(1.5e+025,-3.10504e+231) returns -1.#IND
Floating point math error occurred in your program. More details below:
Total loss of significance:: tan(1.5e+025,-3.10504e+231) returns -1.#IND
Floating point math error occurred in your program. More details below:
Domain Error: : acos(2,-3.10504e+231) returns -1.#IND
Ladd, Scott Robert. C++ I/O Streams, Containers, and Standard Classes. M&T Books.
1996
Musser, David R. and Atul Saini. STL Tutorial and Reference Guide. Addison-Wesley
Plauger, P.J. C++ User’s Journal. Series of articles beginning June, 1996.
Stroustrup, Bjarne. The C++ Programming Language, Second Edition. AT&T. 1993
16.1 deque
Note In the definition below, the template parameter Type represents the type of data the
deque will store (for example, int). The template parameter A represents the allocator
object the deque will use for memory allocation.
16.2 list
Note In the definition below, the template parameter Type represents the type of data the
list will store (for example, int). The template parameter A represents the allocator object
the list will use for memory allocation.
Note In the definitions below, the template parameter K represents the type of data the
map will store (for example, int). The template parameter Pr represents the user-defined
comparator object (for example, less<K>). The template parameter A represents the
allocator object the map will use for memory allocation.
Note In the definitions below, the template parameter K represents the type of data the
set will store (for example, int). The template parameter Pr represents the user-defined
comparator object (for example, less<K>). The template parameter A represents the
allocator object the set will use for memory allocation.
16.5 vector
Note In the definition below, the template parameter Type represents the type of data the
vector will store (for example, int). The template parameter A represents the allocator
object the vector will use for memory allocation.
// TEMPLATE CLASS vector
template<class TYPE, class A>
class vector {
public:
typedef vector<TYPE, A> Myt;
typedef A allocatorTYPE;
typedef A::sizeTYPE sizeTYPE;
typedef A::differenceTYPE differenceTYPE;
typedef A::pointer Tptr;
typedef A::const_pointer Ctptr;
typedef A::reference reference;
typedef A::const_reference const_reference;
typedef A::valueTYPE valueTYPE;
typedef Tptr iterator;
typedef Ctptr const_iterator;
typedef reverse_iterator<const_iterator, valueTYPE,
const_reference,
Ctptr, differenceTYPE> const_reverse_iterator;
typedef reverse_iterator<iterator, valueTYPE, reference, Tptr,
differenceTYPE> reverse_iterator;
explicit vector(const A& Al = A());
explicit vector(sizeTYPE N, const TYPE& V = TYPE(), const A& Al =
A());
vector(const Myt& X);
typedef const_iterator _It;
vector(It F, It L, const A& Al = A());
~vector();
Myt& operator=(const Myt& X);
void reserve(sizeTYPE N);
sizeTYPE capacity() const;
iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;
reverse_iterator rbegin();
const_reverse_iterator rbegin() const;
reverse_iterator rend();
const_reverse_iterator rend() const;
void resize(sizeTYPE N, TYPE X = TYPE());
sizeTYPE size() const;
sizeTYPE max_size() const;
bool empty() const;
A getAllocator() const;
const_reference at(sizeTYPE P) const;
reference at(sizeTYPE P);
const_reference operator[](sizeTYPE P) const;
reference operator[](sizeTYPE P);
reference front();
const_reference front() const;
reference back();
const_reference back() const;
void push_back(const TYPE& X);
void pop_back();
void assign(It F, It L);
void assign(sizeTYPE N, const TYPE& X = TYPE());
iterator insert(iterator P, const TYPE& X = TYPE());
void insert(iterator P, sizeTYPE M, const TYPE& X);
void insert(iterator P, It F, It L);
iterator erase(iterator P);
iterator erase(iterator F, iterator L);
void clear();
void swap(Myt& X);
friend void swap(Myt& X, Myt& Y);
protected:
void _Destroy(iterator F, iterator L);
void _Xran() const;
A allocator;
iterator First, Last, End;
};
// vector TEMPLATE OPERATORS
template<class TYPE, class A> inline bool operator==(const vector<TYPE,
A>& X,
const vector<TYPE, A>& Y);
template<class TYPE, class A> inline bool operator<(const vector<TYPE,
A>& X,
const vector<TYPE, A>& Y);
16.6 stack
Note In the definition below, the template parameter Type represents the type of data the
stack will store (for example, int). The template parameter C represents the container the
stack is adapting (for example, deque). The template parameter A represents the allocator
object the stack will use for memory allocation.
16.7 priority_queue
Note In the definition below, the template parameter Type represents the type of data the
priority_queue will store (for example, int). The template parameter C represents the
container the priority_queue is adapting (for example, deque). The template parameter Pr
represents the user-defined comparator object to order the sequence (for example,
less<TYPE>). The template parameter A represents the allocator object the
priority_queue will use for memory allocation (for example, allocator<TYPE>).
16.8 queue
Note The template parameter Type in the definition below represents the type of data the
queue will store (for example, int). The template parameter C represents the container the
queue is adapting (for example, deque). The template parameter A represents the allocator
object the queue will use for memory allocation.
17.1 deque
Member Description
typedef A allocator_type deque::allocator_type describes the stored
allocator object (same as the second template
argument).
void assign(const_iterator The first version of deque::assign replaces
first,const_iterator the sequence controlled by *this with the
. . . last)void assign(size_type n, const T& sequence [first, last). The second version
x = T()) replaces the sequence controlled by *this
with a repetition of n elements of value x.
const_reference at(size_type pos) deque::at returns a reference to the element
constreference . . . at(size_type pos) of the deque at position pos. If that position
is invalid, the function throws an object of
class out_of_range (throws an exception).
reference back() deque::back returns a reference to the last
const_reference back() const element of the deque, which must be
nonempty.
const_iterator begin() const deque::begin returns a random-access
iterator begin() iterator that points at the first element of the
sequence (or just beyond the end of an
empty sequence).
void clear() const deque::clear calls erase( begin(), end()).
typedef A::const_iterator const_iterator deque::const_iterator describes an object
that can serve as a constant random-access
iterator for the deque. It is described here as
a synonym for the const_iterator member of
the allocator object.
Typedef A::const_reference deque::const_reference describes an object
const_reference that can serve as a constant reference to an
element of the deque.
typedef reverse_iterator<const_iterator, deque::const_reverse_iterator describes an
value_type,const_reference, object that can serve as a constant reverse
A::const_pointer, iterator for the deque.
difference_type>
const_reverse_iterator
explicit deque(const A& al = A()) All constructors store the allocator object al
explicit deque(size_type n, const T& v = (or, for the copy constructor,
T(), x.get_allocator()) in allocator and initialize
const A& al = A()) the controlled sequence. The first constructor
deque(const deque& x) specifies an empty initial controlled
deque(const_iterator first, const_iterator sequence. The second constructor specifies a
last, repetition of n elements of value x. The third
const A& al = A()) constructor specifies a copy of the sequence
controlled by x. The last constructor
specifies the sequence[first, last).
typedef A::difference_type deque::difference_type is a signed integer
difference_type type that describes an object that can
represent the difference between the
addresses of any two elements in the deque.
bool empty() const deque::empty returns true if the deque is
empty.
const_iterator end() const deque::end returns a random-access iterator
iterator end() that points just beyond the end of the
sequence.
iterator erase(iterator it) The first version of deque::erase removes
iterator erase(iterator first, iterator last) the element of the controlled sequence
pointed to by it. The second version removes
the elements of the controlled sequence in
the range [first, last). Both return an iterator
that designates the first element remaining
beyond any elements removed, or end() if no
such element exists.
Erasing N elements causes N destructor calls
and an assignment (operator=) for each of
the elements between the insertion point and
the nearer end of the sequence. Removing an
element at either end invalidates only
iterators and references that designate the
erased elements. Otherwise, erasing an
element invalidates all iterators and
references.
reference front() deque::front returns a reference to the first
const_reference front() const element of the controlled sequence, which
must be nonempty.
A get_allocator() const The member function returns allocator.
iterator insert(iterator it, const T& x = Each version of deque::insert inserts, after
T()) the element pointed to by it in the controlled
void insert(iterator it, size_type n, const sequence, a sequence specified by the
T& x) remaining operands. The first version inserts
void insert(iterator it, const_iterator first, a single element with value x> and returns
const_iterator last) an iterator that points to the newly inserted
element. The second version inserts a
repetition of n elements of value x. The third
version inserts the sequence [first, last).
When inserting a single element, the number
of element copies is linear in the number of
elements between the insertion point and the
nearer end of the sequence. When inserting a
single element at either end of the sequence,
the amortized number of element copies is
constant. When inserting N elements, the
number of element copies is linear in N plus
the number of elements between the
insertion point and the nearer end of the
sequence. Inserting an element at either end
invalidates all iterators, but no references,
that designate existing elements. Otherwise,
inserting an element invalidates all iterators
and references.
typedef A::pointer iterator Iterator describes an object that can serve as
a random-access iterator for the controlled
sequence. It is described here as a synonym
for the pointer member of the allocator
object.
size_type max_size() const deque::max_size returns the length of the
longest sequence that the object can control.
const_reference operator[](size_type pos) operator[] returns a reference to the element
const of the controlled sequence at position pos. If
reference operator[](size_type pos) that position is invalid, the behavior is
undefined.
void pop_back() deque::pop_back removes the last element
of the controlled sequence, which must be
nonempty. Removing the element invalidates
only iterators and references that designate
the erased element.
void pop_front() deque::pop_front removes the first element
of the controlled sequence, which must be
nonempty. Removing the element invalidates
only iterators and references that designate
the erased element.
void push_back(const T& x) deque::push_back inserts an element with
value x at the end of the controlled sequence.
Inserting the element invalidates all iterators,
but no references, to existing elements.
void push_front(const T& x) deque::push_front inserts an element with
value x at the beginning of the controlled
sequence. Inserting the element invalidates
all iterators, but no references, to existing
elements.
const_reverse_iterator rbegin() const deque::rbegin returns a reverse iterator that
reverse_iterator rbegin() points just beyond the end of the controlled
sequence. Hence, it designates the beginning
of the reverse sequence.
typedef A::reference reference deque::reference describes an object that
can be used as a reference to an element of
the controlled sequence. It is described here
as a synonym for the reference member of
the allocator object.
const_reverse_iterator rend() const deque::rend returns a reverse iterator that
reverse_iterator rend() points at the first element of the sequence (or
just beyond the end of an empty sequence).
Hence, it designates the end of the reverse
sequence.
void resize(size_type n, T x = T()) deque::resize ensures that size() henceforth
returns n. If it must make the controlled
sequence longer, it appends elements with
value x.
typedef reverse_iterator<iterator, The type describes an object that can serve
value_type, as a reverse iterator for the controlled
reference, A::types<T>::pointer, sequence.
difference_type> reverse_iterator
size_type size() const deque::size returns the length of the
controlled sequence.
typedef A::size_type size_type size_type is an unsigned integer type that
describes an object that can represent the
length of any controlled sequence.
void swap(deque& str) deque::swap swaps the controlled
sequences between *this and str. If allocator
== str.allocator, it does so in constant time.
Otherwise, it performs a number of element
assignments and constructor calls
proportional to the number of elements in
the two controlled sequences.
typedef A::types<T>::value_type The type describes an element of the
value_type controlled sequence (same as the template
parameter T).
17.2 list
Member Description
typedef A allocator_type list::allocator_type describes the stored
allocator object (same as the second
template argument).
void assign(const_iterator first,const_iterator The first version of list::assign replaces
last) the sequence controlled by *this with the
void assign(size_type n, const T& x = T()) sequence [first, last). The second version
replaces the sequence controlled by *this
with a repetition of n elements of value x.
reference back() list::back returns a reference to the last
const_reference back() const element of the list, which must be
nonempty.
const_iterator begin() const list::begin returns a random-access
iterator begin() iterator that points at the first element of
the sequence (or just beyond the end of
an empty sequence).
void clear() const list::clear calls erase( begin(), end()).
typedef A::const_iterator const_iterator list::const_iterator describes an object
that can serve as a constant random-
access iterator for the list. It is described
here as a synonym for the const_iterator
member of the allocator object.
typedef A::const_reference const_reference list::const_reference describes an object
that can serve as a constant reference to
an element of the list.
typedef reverse_iterator<const_iterator, list::const_reverse_iterator describes
value_type,const_reference, an object that can serve as a constant
A::const_pointer, reverse iterator for the list.
difference_type> const_reverse_iterator
typedef A::difference_type difference_type list::difference_type is a signed integer
type that describes an object that can
represent the difference between the
addresses of any two elements in the list.
bool empty() const list::empty returns true if the list is
empty
const_iterator end() const list::end returns a random-access iterator
iterator end() that points just beyond the end of the
sequence.
iterator erase(iterator it) The first version of list::erase removes
iterator erase(iterator first, iterator last) the element of the controlled sequence
pointed to by it. The second version
removes the elements of the controlled
sequence in the range [first, last). Both
return an iterator that designates the first
element remaining beyond any elements
removed, or end() if no such element
exists.
Erasing N elements causes N destructor
calls. No reallocation occurs, so iterators
and references become invalid only for
the erased elements.
reference front() list::front returns a reference to the first
const_reference front() const element of the controlled sequence,
which must be nonempty.
A get_allocator() const The member function returns allocator.
iterator insert(iterator it, const T& x = T()) Each version of list::insert inserts, after
void insert(iterator it, size_type n,const T& the element pointed to by it in the
x) controlled sequence, a sequence
void insert(iterator it, const_iterator first, specified by the remaining operands. The
const_iterator last) first version inserts a single element with
value x> and returns an iterator that
points to the newly inserted element. The
second version inserts a repetition of n
elements of value x. The third version
inserts the sequence [first, last).
Inserting N elements causes N copies. No
reallocation occurs, so no iterators or
references become invalid.
typedef A::pointer iterator Iterator describes an object that can serve
as a random-access iterator for the
controlled sequence. It is described here
as a synonym for the pointer member of
the allocator object.
explicit list(const A& al = A()) All constructors store the allocator object
explicit list(size_type n, const T& v = T(), al (or, for the copy constructor,
const A& al = A()) x.get_allocator()) in allocator and
list(const list& x) initialize the controlled sequence. The
list(const_iterator first, const_iterator last, first constructor specifies an empty initial
const A& al = A()) controlled sequence. The second
constructor specifies a repetition of n
elements of value x. The third
constructor specifies a copy of the
sequence controlled by x. The last
constructor specifies the sequence [first,
last). None of the constructors perform
any interim reallocations.
size_type max_size() const list::max_size returns the length of the
longest sequence that the object can
control.
void merge(list& x) Both versions of list::merge remove all
void merge(list& x, greater<TYPE> pr) elements from the sequence controlled
by x and insert them in the controlled
sequence. Both sequences must be
ordered by the same predicate, described
below. The resulting sequence is also
ordered by that predicate. For the
iterators Pi and Pj designating elements
at positions i and j, the first member
function imposes the order !(*Pj < *Pi)
whenever i < j. The second version
imposes the order !pr(*Pj, *Pi)
whenever i < j. No pairs of elements in
the original controlled sequence are
reversed in the resulting controlled
sequence. If a pair of elements in the
resulting controlled sequence compares
equal (!(*Pi < *Pj) && !(*Pj < *Pi)), an
element from the original controlled
sequence appears before an element from
the sequence controlled by x.
void pop_back() list::pop_back removes the last element
of the controlled sequence, which must
be nonempty.
void pop_front() list::pop_front removes the first element
of the controlled sequence, which must
be nonempty.
void push_back(const T& x) list::push_back inserts an element with
value x at the end of the controlled
sequence.
void push_front(const T& x) list::push_front inserts an element with
value x at the beginning of the controlled
sequence.
const_reverse_iterator rbegin() const list::rbegin returns a reverse iterator that
reverse_iterator rbegin() points just beyond the end of the
controlled sequence. Hence, it designates
the beginning of the reverse sequence.
typedef A::reference reference list::reference describes an object that
can be used as a reference to an element
of the controlled sequence. It is described
here as a synonym for the reference
member of the allocator object.
void remove(const T& x) list::remove removes from the
controlled sequence all elements,
designated by the iterator P, for which
*P == x.
void remove_if( list::remove_if removes from the
binder2nd<not_equal_to<TYPE> > pr) controlled sequence all elements,
designated by the iterator P, for which
pr(*P) is true.
const_reverse_iterator rend() const list::rend returns a reverse iterator that
reverse_iterator rend() points at the first element of the sequence
(or just beyond the end of an empty
sequence). Hence, it designates the end
of the reverse sequence.
void resize(size_type n, T x = T()) list::resize ensures that size() henceforth
returns n. If it must make the controlled
sequence longer, it appends elements
with value x.
void reverse() list::reverse reverses the order in which
elements appear in the controlled
sequence.
typedef reverse_iterator<iterator, The type describes an object that can
value_type, serve as a reverse iterator for the
reference, A::types<T>::pointer, controlled sequence.
difference_type> reverse_iterator
size_type size() const list::size returns the length of the
controlled sequence.
typedef A::size_type size_type size_type is an unsigned integer type that
describes an object that can represent the
length of any controlled sequence.
void sort() Both versions of list::sort order the
void sort(greater<TYPE> pr) elements in the controlled sequence by a
predicate. For the iterators Pi and Pj
designating elements at positions i and j,
the first member function imposes the
order !(*Pj < *Pi) whenever i < j. The
second version imposes the order !
pr(*Pj, *Pi) whenever i < j. No pairs of
elements in the original controlled
sequence are reversed in the resulting
controlled sequence. "void splice(iterator
it, list& x)"
void splice(iterator it, list& x, iterator first) The first version of list::splice inserts the
void splice(iterator it,iterator first,iterator sequence controlled by x after the
last) element in the controlled sequence
pointed to by it. It also removes all
elements from x. (&x must not equal
this). The second version removes the
element pointed to by the first in the
sequence controlled by x and inserts it
after the element in the controlled
sequence pointed to by it. (If it == first ||
it == ++first, no change occurs). The
third version function inserts the
subrange designated by [first, last) from
the sequence controlled by x after the
element in the controlled sequence
pointed to by it. It also removes the
original subrange from the sequence
controlled by x. (If &x == this, the range
[first, last) must not include the element
pointed to by it). If the third version
inserts N elements, and &x != this, an
object of class iterator is incremented N
times. In no case do any copies or
destructor calls occur for any elements.
void swap(list& str) list::swap swaps the controlled
sequences between *this and str. If
allocator == str.allocator, it does so in
constant time. Otherwise, it performs a
number of element assignments and
constructor calls proportional to the
number of elements in the two controlled
sequences.
void unique() The first version of list::unique removes
void unique(not_equal_to<TYPE>pr) from the controlled sequence every
element that compares equal to its
preceding element. For the iterators Pi
and Pj designating elements at positions
i and j, the second version removes every
element for which i + 1 == j && pr(*Pi,
*Pj). For a list of length N (> 0), the
predicate pr(*Pi, *Pj) is evaluated N - 1
times.
typedef A::types<T>::value_type value_type The type describes an element of the
controlled sequence (same as the
template parameter T).
Member: Description
typedef A allocator_type map::allocator_type describes the stored
allocator object (same as the fourth template
argument).
const_iterator begin() const map::begin returns a bidirectional iterator
iterator begin() that points at the first element of the sequence
(or just beyond the end of an empty
sequence).
void clear() const map::clear calls erase( begin(), end()).
typedef A::const_iterator const_iterator map::const_iterator describes an object that
can serve as a constant bidirectional iterator
for the map. It is described here as a synonym
for the const_iterator member of the
allocator object.
typedef A::const_reference map::const_reference describes an object
const_reference that can serve as a constant reference to an
element of the map.
typedef map::const_reverse_iterator describes an
reverse_iterator<const_iterator, object that can serve as a constant reverse
value_type, const_reference, bidirectional iterator for the map.
A::const_pointer, difference_type>
const_reverse_iterator
size_type count(const Key& key) const map::count returns the number of elements x
in the range [lower_bound(key),
upper_bound(key)).
typedef A::difference_type map::difference_type is a signed integer
difference_type type that describes an object that can
represent the difference between the
addresses of any two elements in the map.
Note that such differences are not meaningful
within the context of the map.
bool empty() const map::empty returns true if the map is empty.
const_iterator end() const map::end returns a bidirectional iterator that
iterator end() points just beyond the end of the sequence.
pair<const_iterator, const_iterator> map::equal_range returns a pair of iterators
equal_range(const Key& key) const x such that x.first == lower_bound(key) and
x.second == upper_bound(key).
iterator erase(iterator it) The first version of map::erase removes the
iterator erase(iterator first, iterator last) element of the controlled sequence pointed to
size_type erase(const Key& key) by it. The second version removes the
elements in the range [first, last). Both return
an iterator that designates the first element
remaining beyond any elements removed, or
end() if no such element exists. The third
version removes the elements with sort keys
in the range [lower_bound(key),
upper_bound(key)), and returns the number
of elements it removes.
const_iterator find(const Key& key) map::find returns an iterator that designates
const the earliest element in the controlled sequence
whose sort key equals key. If no such element
exists, the iterator equals end().
A get_allocator() const The member function returns allocator.
pair<iterator, bool> The first version of map::insert determines
insert(const value_type& x) whether an element y exists in the sequence
iterator insert(iterator obptr, whose key matches that of x. (The keys match
const value_type& x) if ! key_comp()(x, y) && !key_comp()(y,
void insert(const value_type *first, x).) If not, it creates such an element y and
const value_type *last) initializes it with x. The function then
determines the iterator obptr that designates y.
If an insertion occurred, the function returns
pair(obptr, true). Otherwise, it returns
pair(obptr, false). The second version returns
insert(x), using obptr as a starting place
within the controlled sequence to search for
the insertion point. (Insertion can occur in
amortized constant time, instead of
logarithmic time, if the insertion point
immediately follows obptr.) The third version
inserts the sequence of element values in the
range [first, last).
typedef A::pointer iterator Iterator describes an object that can serve as
a bidirectional iterator for the controlled
sequence. It is described here as a synonym
for the pointer member of the allocator
object.
key_compare key_comp() const map::key_comp returns the stored function
object that determines the order of elements
in the controlled sequence. The stored object
defines the member function bool
operator(const Key& x, const Key& y)
which returns true if x strictly precedes y in
the sort order.
typedef Pred key_compare map::key_compare describes a function
object that can compare two sort keys to
determine the relative order of any two
elements in the controlled sequence. It is
described here in terms of the user-defined
comparator object (second template
parameter).
typedef Key key_type map::key_type describes the sort key object
stored in each element of the map.
const_iterator lower_bound map::lower_bound returns an iterator that
(const Key& key) const designates the earliest element x in the
controlled sequence for which key_comp()(x,
key) is False. If no such element exists, the
function returns end().
explicit map(const Pred& comp = The constructors with an argument named
Pred(), comp store the function object so that it can
const A& al=A()) be later returned by calling key_comp(). All
map(const map& x) constructors also store the allocator object al
map(const value_type *first,const (or, for the copy constructor, x.
value_type *last, get_allocator()) in allocator and initialize the
const Pred& comp=Pred(), const A& controlled sequence. The first constructor
al=A()) specifies an empty initial controlled
sequence. The second constructor specifies a
copy of the sequence controlled by x. The
third constructor specifies the sequence of
element values [first, last).
This method is a member of map only.
typedef TYPE mapped_type map::mapped_type describes the value
object stored in each element of the map. It is
described here in terms of the second
template parameter.
size_type max_size() const map::max_size returns the length of the
longest sequence that the object can control.
explicit multimap(const Pred& comp = The constructors with an argument named
Pred(), comp store the function object so that it can
const A& al=A()) be later returned by calling key_comp(). All
multimap(const multimap& x) constructors also store the allocator object al
multimap(const value_type *first, (or, for the copy constructor, x.
const value_type *last, get_allocator()) in allocator and initialize the
const Pred& comp=Pred(), const A& controlled sequence. The first constructor
al=A()) specifies an empty initial controlled
sequence. The second constructor specifies a
copy of the sequence controlled by x. The
third constructor specifies the sequence of
element values [first, last).
This method is a member of multimap only.
A::types<TYPE>::reference map::operator[] determines the iterator it as
operator[](const Key& key); the return value of insert( value_type(key,
T()). (It inserts an element with the specified
key if no such element exists.) It then returns
a reference to (*it). second.
This method is a member of map only.
const_reverse_iterator rbegin() const map::rbegin returns a reverse iterator that
reverse_iterator rbegin() points just beyond the end of the controlled
sequence. Hence, it designates the beginning
of the reverse sequence.
typedef A::reference reference map::reference describes an object that can
be used as a reference to an element of the
controlled sequence. It is described here as a
synonym for the reference member of the
allocator object.
const_reverse_iterator rend() const map::rend returns a reverse iterator that
reverse_iterator rend() points at the first element of the sequence (or
just beyond the end of an empty sequence).
Hence, it designates the end of the reverse
sequence.
typedef reverse_bidirectional_iterator map::reverse_iterator describes an object
<iterator, value_type, reference, that can serve as a reverse bidirectional
A::types<Key>::pointer, iterator for the controlled sequence.
difference_type> reverse_iterator
explicit map(const Pred& comp=Pred(), The constructors with an argument named
const A& al=A()) comp store the function object so that it can
map(const map& x) be later returned by calling key_comp(). All
map(const value_type *first,const constructors also store the allocator object al
value_type *last, (or, for the copy constructor,
const Pred& comp = Pred(), const A& x.get_allocator()) in allocator and initialize
al = A()) the controlled sequence. The first constructor
specifies an empty initial controlled
sequence. The second constructor specifies a
copy of the sequence controlled by x. The
third constructor specifies the sequence of
element values [first, last).
This method is a member of map only.
size_type size() const map::size returns the length of the controlled
sequence.
typedef A::size_type size_type size_type is an unsigned integer type that
describes an object that can represent the
length of any controlled sequence.
void swap(map& str) map::swap swaps the controlled sequences
between *this and str. If allocator ==
str.allocator, it does so in constant time.
Otherwise, it performs a number of element
assignments and constructor calls
proportional to the number of elements in the
two controlled sequences.
const_iterator upper_bound(const Key& map::upper_bound returns an iterator that
key) const designates the earliest element x in the
controlled sequence for which
key_comp()(key, x) is true. If no such
element exists, the function returns end().
value_compare value_comp() const map::valuecomp returns a function object
that determines the order of elements in the
controlled sequence.
class value_compare map::value_compare describes a function
: public binary_function<value_type, object that can compare the sort keys in two
value_type, bool> { elements to determine their relative order in
friend class map; the controlled sequence. The function object
public: stores an object comp of type key_type. The
bool operator()(const value_type& x, member function operator() uses this object
const value_type& y) to compare the sort-key components of two
{return (comp(x.first, x.second)); } elements.
protected:
value_compare(key_compare pr)
: comp(pr) {}
key_compare comp;
};
typedef pair<const Key, T> value_type; The type describes an element of the
controlled sequence (a key/data pair).
Each element listed here is a member of both set and multiset, with exceptions noted
explicitly. References to set::[symbol] imply the existence of multiset::[symbol] with
similar behavior.
Member Function
typedef A allocator_type set::allocator_type describes the stored
allocator object (same as the second
template argument).
const_iterator begin() const set::begin returns a bidirectional iterator
iterator begin() that points at the first element of the
sequence (or just beyond the end of an
empty sequence).
void clear() const set::clear calls erase( begin(), end()).
typedef A::const_iterator const_iterator set::const_iterator describes an object that
can serve as a constant bidirectional iterator
for the set. It is described here as a
synonym for the const_iterator member of
the allocator object.
typedef A::const_reference set::const_reference describes an object
const_reference that can serve as a constant reference to an
element of the set.
typedef reverse_iterator<const_iterator, set::const_reverse_iterator describes an
value_type,const_reference, object that can serve as a constant reverse
A::const_pointer, bidirectional iterator for the set.
difference_type>
const_reverse_iterator
size_type count(const Key& key) const set::count returns the number of elements x
in the range [lower_bound(key),
upper_bound(key)).
typedef A::difference_type difference_type set::difference_type is a signed integer
type that describes an object that can
represent the difference between the
addresses of any two elements in the set.
Note that such differences are not
meaningful within the context of the set.
bool empty() const set::empty returns true if the set is empty
const_iterator end() const set::end returns a bidirectional iterator that
iterator end() points just beyond the end of the sequence.
pair<const_iterator, const_iterator> set::equal_range returns a pair of iterators
equal_range(const Key& key) const x such that x.first == lower_bound(key)
and x.second == upper_bound(key).
iterator erase(iterator it) The first version of set::erase removes the
iterator erase(iterator first, iterator last) element of the controlled sequence pointed
size_type erase(const Key& key) to by it. The second version removes the
elements in the range [first, last). Both
return an iterator that designates the first
element remaining beyond any elements
removed, or end() if no such element exists.
The third version removes the elements
with sort keys in the range
[lower_bound(key), upper_bound(key)),
and returns the number of elements it
removes.
const_iterator find(const Key& key) const set::find returns an iterator that designates
the earliest element in the controlled
sequence whose sort key equals key. If no
such element exists, the iterator equals
end().
A get_allocator() const The member function returns allocator.
pair<iterator, bool> The first version of set::insert determines
insert(const value_type& x) whether an element y exists in the sequence
iterator insert(iterator obptr, const whose key matches that of x. (The keys
value_type& x) match if ! key_comp()(x, y) && !
void insert(const value_type *first, key_comp()(y, x).) If not, it creates such an
const value_type *last) element y and initializes it with x. The
function then determines the iterator obptr
that designates y. If an insertion occurred,
the function returns pair(obptr, true).
Otherwise, it returns pair(obptr, false). The
second version returns insert(x), using
obptr as a starting place within the
controlled sequence to search for the
insertion point. (Insertion can occur in
amortized constant time, instead of
logarithmic time, if the insertion point
immediately follows obptr.) The third
version inserts the sequence of element
values in the range [first, last).
typedef A::pointer iterator Iterator describes an object that can serve
as a bidirectional iterator for the controlled
sequence. It is described here as a synonym
for the pointer member of the allocator
object.
key_compare key_comp() const map::key_comp returns the stored function
object that determines the order of elements
in the controlled sequence. The stored
object defines the member function bool
operator(const Key& x, const Key& y),
which returns true if x strictly precedes y in
the sort order.
typedef Pred key_compare map::key_compare describes a function
object that can compare two sort keys to
determine the relative order of any two
elements in the controlled sequence. It is
described here in terms of the user-defined
comparator object (second template
parameter).
typedef Key key_type map::key_type describes the sort key
object that constitutes each element of the
controlled sequence. It is described here in
terms of the data type of the objects the set
contains (first template parameter).
const_iterator lower_bound(const Key& set::lower_bound returns an iterator that
key) designates the earliest element x in the
const controlled sequence for which
key_comp()(x, key) is False. If no such
element exists, the function returns end().
size_type max_size() const set::max_size returns the length of the
longest sequence that the object can control.
explicit multiset(const Pred& comp = The constructors with an argument named
Pred(), comp store the function object so that it can
const A& al=A()) be later returned by calling key_comp(). All
multiset(const multiset& x) constructors also store the allocator object
multiset(const value_type *first, al (or, for the copy constructor, x.
const value_type *last, get_allocator()) in allocator and initialize
const Pred& comp=Pred(), const A& the controlled sequence. The first
al=A()) constructor specifies an empty initial
controlled sequence. The second
constructor specifies a copy of the sequence
controlled by x. The third constructor
specifies the sequence of element values
[first, last).
This method is a member of multiset only
const_reverse_iterator rbegin() const set::rbegin returns a reverse iterator that
reverse_iterator rbegin() points just beyond the end of the controlled
sequence. Hence, it designates the
beginning of the reverse sequence.
typedef A::reference reference set::reference describes an object that can
be used as a reference to an element of the
controlled sequence. It is described here as
a synonym for the reference member of the
allocator object.
const_reverse_iterator rend() const set::rend returns a reverse iterator that
reverse_iterator rend() points at the first element of the sequence
(or just beyond the end of an empty
sequence). Hence, it designates the end of
the reverse sequence.
typedef set::reverse_iterator describes an object
reverse_bidirectional_iterator<iterator, that can serve as a reverse bidirectional
value_type, reference, iterator for the controlled sequence.
A::types<Key>::pointer,
difference_type> reverse_iterator
explicit set(const Pred& comp=Pred(), The constructors with an argument named
const A& al=A()) comp store the function object so that it can
set(const set& x) be later returned by calling key_comp(). All
set(const value_type *first, const constructors also store the allocator object
value_type *last, al (or, for the copy constructor,
const Pred& comp = Pred(), x.get_allocator()) in allocator and initialize
const A& al = A()) the controlled sequence. The first
constructor specifies an empty initial
controlled sequence. The second
constructor specifies a copy of the sequence
controlled by x. The third constructor
specifies the sequence of element values
[first, last).
This method is a member of set only.
size_type size() const set::size returns the length of the controlled
sequence.
typedef A::size_type size_type size_type is an unsigned integer type that
describes an object that can represent the
length of any controlled sequence.
void swap(set& str) set::swap swaps the controlled sequences
between *this and str. If allocator ==
str.allocator, it does so in constant time.
Otherwise, it performs a number of element
assignments and constructor calls
proportional to the number of elements in
the two controlled sequences.
const_iterator upper_bound(const Key& set::upper_bound returns an iterator that
key) const designates the earliest element x in the
controlled sequence for which
key_comp()(key, x) is true. If no such
element exists, the function returns end().
value_compare value_comp() const set::valuecomp returns a function object
that determines the order of elements in the
controlled sequence.
typedef Pred value_compare set::value_compare describes a function
object that can compare two elements as
sort keys to determine their relative order in
the controlled sequence. It is described
herein as the user-defined comparator
object (second template parameter).
typedef A::types<T>::value_type The type describes an element of the
value_type controlled sequence (same as the template
parameter T).
17.5 vector
Member Description
typedef A allocator_type vector::allocator_type describes the
stored allocator object (same as the second
template argument).
void assign(const_iterator first, The first version of vector::assign
const_iterator last) replaces the sequence controlled by *this
void assign(size_type n, const T& x = T()) with the sequence [first, last). The second
version replaces the sequence controlled
by *this with a repetition of n elements of
value x.
const_reference at(size_type pos) const vector::at returns a reference to the
reference at(size_type pos) element of the vector at position pos. If
that position is invalid, the function throws
an object of class out_of_range (throws an
exception).
reference back() vector::back returns a reference to the last
const_reference back() const element of the vector, which must be
nonempty.
const_iterator begin() const vector::begin returns a random-access
iterator begin() iterator that points at the first element of
the sequence (or just beyond the end of an
empty sequence).
size_type capacity() const vector::capacity returns the storage
currently allocated to hold the vector, a
value at least as large as vector::size().
void clear() const vector::clear calls erase( begin(), end()).
typedef A::const_iterator const_iterator vector::const_iterator describes an object
that can serve as a constant random-access
iterator for the vector. It is described here
as a synonym for the const_iterator
member of the allocator object.
typedef A::const_reference const_reference vector::const_reference describes an
object that can serve as a constant
reference to an element of the vector.
typedef reverse_iterator<const_iterator, vector::const_reverse_iterator describes
value_type, const_reference, an object that can serve as a constant
A::const_pointer, reverse iterator for the vector.
difference_type> const_reverse_iterator
typedef A::difference_type difference_type vector::difference_type is a signed
integer type that describes an object that
can represent the difference between the
addresses of any two elements in the
vector.
bool empty() const vector::empty returns true if the vector is
empty
const_iterator end() const vector::end returns a random-access
iterator end() iterator that points just beyond the end of
the sequence.
iterator erase(iterator it) The first version of vector::erase removes
iterator erase(iterator first, iterator last) the element of the controlled sequence
pointed to by it. The second version
removes the elements of the controlled
sequence in the range [first, last). Both
return an iterator that designates the first
element remaining beyond any elements
removed, or end() if no such element
exists.
Erasing N elements causes N destructor
calls and an assignment (operator=) for
each of the elements between the insertion
point and the end of the sequence. No
reallocation occurs, so iterators and
references become invalid only from the
first element erased through the end of the
sequence.
reference front() vector::front returns a reference to the
const_reference front() const first element of the controlled sequence,
which must be nonempty.
A get_allocator() const The member function returns allocator.
iterator insert(iterator it, const T& x = T()) Each version of vector::insert inserts,
void insert(iterator it, size_type n, const after the element pointed to by it in the
T& x) controlled sequence, a sequence specified
void insert(iterator it, const_iterator first, by the remaining operands. The first
const_iterator last) version inserts a single element with value
x> and returns an iterator that points to the
newly inserted element. The second
version inserts a repetition of n elements of
value x. The third version inserts the
sequence [first, last).
When inserting a single element, the
number of element copies is linear in the
number of elements between the insertion
point and the end of the sequence. When
inserting a single element at the end of the
sequence, the amortized number of
element copies is constant. When inserting
N elements, the number of element copies
is linear in N plus the number of elements
between the insertion point and the end of
the sequence.
If reallocation occurs, the size of the
controlled sequence at least doubles, and
all iterators and references become invalid.
If no reallocation occurs, iterators become
invalid only from the point of insertion
through the end of the sequence.
typedef A::pointer iterator Iterator describes an object that can serve
as a random-access iterator for the
controlled sequence. It is described here as
a synonym for the pointer member of the
allocator object.
size_type max_size() const vector::max_size returns the length of the
longest sequence that the object can
control.
const_reference operator[](size_type pos) operator[] returns a reference to the
const element of the controlled sequence at
reference operator[](size_type pos) position pos. If that position is invalid, the
behavior is undefined.
void pop_back() vector::pop_back removes the last
element of the controlled sequence, which
must be nonempty.
void push_back(const T& x) vector::push_back inserts an element
with value x at the end of the controlled
sequence.
const_reverse_iterator rbegin() const vector::rbegin returns a reverse iterator
reverse_iterator rbegin() that points just beyond the end of the
controlled sequence. Hence, it designates
the beginning of the reverse sequence.
typedef A::reference reference vector::reference describes an object that
can be used as a reference to an element of
the controlled sequence. It is described
here as a synonym for the reference
member of the allocator object.
const_reverse_iterator rend() const vector::rend returns a reverse iterator that
reverse_iterator rend() points at the first element of the sequence
(or just beyond the end of an empty
sequence). Hence, it designates the end of
the reverse sequence.
void reserve(size_type n) vector::reserve ensures that capacity()
henceforth returns at least n.
void resize(size_type n, T x = T()) vector::resize ensures that size()
henceforth returns n. If it must make the
controlled sequence longer, it appends
elements with value x.
typedef reverse_iterator<iterator, The type describes an object that can serve
value_type, as a reverse iterator for the controlled
sequence.
reference, A::types<T>::pointer,
difference_type> reverse_iterator
size_type size() const vector::size returns the length of the
controlled sequence.
typedef A::size_type size_type size_type is an unsigned integer type that
describes an object that can represent the
length of any controlled sequence.
void swap(vector& str) vector::swap swaps the controlled
sequences between *this and str. If
allocator == str.allocator, it does so in
constant time. Otherwise, it performs a
number of element assignments and
constructor calls proportional to the
number of elements in the two controlled
sequences.
typedef A::types<T>::value_type The type describes an element of the
value_type controlled sequence (same as the template
parameter T).
explicit vector(const A& al = A()) All constructors store the allocator object
explicit vector(size_type n, const T& v = al (or, for the copy constructor,
T(), x.get_allocator()) in allocator and
const A& al = A()) initialize the controlled sequence. The first
vector(const vector& x) constructor specifies an empty initial
vector(const_iterator first, const_iterator controlled sequence. The second
last, constructor specifies a repetition of n
const A& al = A()) elements of value x. The third constructor
specifies a copy of the sequence controlled
by x. The last constructor specifies the
sequence [first, last).
Constructors copy N elements and perform
no interim reallocation.
17.6 priority_queue
Member Description
typedef A allocator_type priority_queue::allocator describes the
allocator object used to construct the stored
container object (specified by the second
template parameter). The allocator is specified
by the third template parameter.
bool empty() const priority_queue::empty returns true if the
priority_queue is empty. Returns C.empty(),
where C is the stored container object
specified by priority_queue’s second
template parameter.
A get_allocator() const; priority_queue::get_allocator returns
C.get_allocator(), where C is the stored
container object specified by priority_queue’s
second template parameter.
void pop(); priority_queue::pop removes the first
element of the controlled sequence, which
must be nonempty, then reorders it.
explicit priority_queue(const Pred& Both constructors store pr in comp and
pr=Pred(), effectively initialize the stored object with
const A& al = A()); c(al), to specify an empty initial controlled
priority_queue(const value_type *first, sequence. The second constructor then calls
const value_type *last, const push(x) where x is an iterator of class InIt in
Pred& pr = the range [first, last).
Pred(), const A& al = A());
void push(const T& x); priority_queue::push inserts an element with
value x at the end of the controlled sequence,
then reorders it.
size_type size() const; priority_queue::size returns the number of
items on the priority_queue. Calls C.size,
where C is the stored container object
specified by priority_queue’s second
template parameter.
typedef C::size_type size_type; priority_queue::size_type describes an
unsigned integer type describes an object that
can represent the length of any controlled
sequence. It is defined here in terms of the
size_type defined for the stored container
object specified by priority_queue’s second
template parameter.
value_type& top(); priority_queue::top returns a reference to the
const value_type& top() const; last element of the priority_queue, which
must be nonempty. Calls C.back(), where C is
the stored container object specified by the
second template parameter.
typedef Cont::value_type value_type; priority_queue::value_type describes an
element of the controlled sequence. In this
context, it is the same as priority_queue’s
first template parameter.
17.7 queue
Member Description
typedef A allocator_type queue::allocator describes the allocator
object used to construct the stored container
object (specified by the second template
parameter). The allocator is specified by the
third template parameter.
bool empty() const queue::empty returns true if the queue is
empty. Returns C.empty(), where C is the
stored container object specified by queue’s
second template parameter.
value_type& front(); queue::front returns a reference to the first
const value_type& front() const; element of the queue, which must be
nonempty. Calls C.back(), where C is the
stored container object specified by the second
template parameter. (see note at the bottom of
this table)
A get_allocator() const; queue::get_allocator returns
C.get_allocator(), where C is the stored
container object specified by queue’s second
template parameter.
void pop(); queue::pop removes the first element from
the queue, which must be nonempty. Calls
C.pop_front, where C is the stored container
object specified by queue’s second template
parameter.
void push(const T& x); queue::push(x) pushes an item with value x
onto the queue. Calls C.push_back(x), where
C is the stored container object specified by
queue’s second template parameter.
explicit queue(const A& al = A()); The constructor initializes the stored container
object C, by calling C.C(al), to specify an
empty initial controlled sequence.
size_type size() const; queue::size returns the number of items on the
queue. Calls C.size, where C is the stored
container object specified by queue’s second
template parameter.
typedef C::size_type size_type; queue::size_type describes an unsigned
integer type that describes an object that can
represent the length of any controlled
sequence. It is defined here in terms of the
size_type defined for the stored container
object specified by queue’s second template
parameter.
typedef Cont::value_type value_type; queue::value_type describes an element of
the controlled sequence. In this context, it is
the same as queue’s first template parameter.
Note Books online for Visual C++ 4.2 says that the queue class has a top member
function (like a stack). This is an error in books online. The ANSII working papers
specify that queue has a front (and not a top) member function.
17.8 stack
Member Description
typedef A allocator_type stack::allocator describes the allocator object
used to construct the stored container object
(specified by the second template parameter).
The allocator is specified by the third template
parameter.
bool empty() const stack::empty returns true if the stack is
empty. Returns C.empty(), where C is the
stored container object specified by stack’s
second template parameter.
A get_allocator() const; stack::get_allocator returns
C.get_allocator(), where C is the stored
container object specified by stack’s second
template parameter.
void pop(); stack::pop removes the last element pushed
onto the stack, which must be nonempty. Calls
C.pop_back, where C is the stored container
object specified by stack’s second template
parameter.
void push(const T& x); stack::push(x) pushes an item with value x
onto the stack. Calls C.push_back(x), where
C is the stored container object specified by
stack’s second template parameter.
size_type size() const; stack::size returns the number of items on the
stack. Calls C.size, where C is the stored
container object specified by stack’s second
template parameter.
typedef C::size_type size_type; stack::size_type describes an unsigned integer
type that describes an object that can represent
the length of any controlled sequence. It is
defined here in terms of the size_type defined
for the stored container object specified by
stack’s second template parameter.
explicit stack(const A& al = A()); The constructor initializes the stored container
object C, by calling C.C(al), to specify an
empty initial controlled sequence.
value_type& top(); stack::top returns a reference to the last
const value_type& top() const; element of the stack, which must be nonempty.
Calls C.back(), where C is the stored
container object specified by the second
template parameter.
typedef Cont::value_type value_type; stack::value_type describes an element of the
controlled sequence. In this context, it is the
same as stack’s first template parameter.
The class allocator as specified by the ANSII draft standard utilizes member templates.
Visual C++ version 4.2 does not support the use of member templates. (The term member
template refers to one or more methods of a (possibly nontemplated) class that are
defined as templated functions. It can also be used to describe a class that has an
embedded template class.)
Since it is not possible to implement the class allocator directly, allocator has been
implemented as a template class in the current implementation of the STL. The problem
lies in attempting to use the templated allocator class as a default template argument.
Consider the following:
This new construct with the template allocator class creates a circular reference, because
it relies on the unknown data type T to instantiate the allocator class. This makes it
necessary, in the case of STL containers, to remove the default template argument for the
allocator. The definition of vector now becomes:
Therefore, declaring a container will now require that you explicitly specify the allocator
class as a template argument, as the following declaration of an int vector illustrates:
vector<int> myVector;
Note The STL is an emerging technology. The definition of the allocator class as a
templated class will undoubtedly change in a future release of Visual C++. You should
always use typedefs when using any component of the STL—this will make it relatively
painless to update your code if and when the templates change.