Don't hesitate to send in feedback: send an e-mail if you like the C++ Annotations; if you think that important material was omitted; if you find errors or typos in the text or the code examples; or if you just feel like e-mailing. Send your e-mail to Frank B. Brokken.Please state the document version you're referring to, as found in the title (in this document: 6.2.3) and please state chapter and paragraph name or number you're referring to.
All received mail is processed conscientiously, and received suggestions for improvements will usually have been processed by the time a new version of the Annotations is released. Except for the incidental case I will normally not acknowledge the receipt of suggestions for improvements. Please don't interpret this as me not appreciating your efforts.
The
Standard Template Library (
STL) consists of
containers,
generic algorithms,
iterators,
function objects,
allocators and
adaptors. The STL is a
general purpose library
consisting of
algorithms and
data structures. The data structures used
in the algorithms are abstract in the sense that the algorithms can be
used on (practically) every data type.
The algorithms can work on these abstract data types due to the fact that they are template based algorithms. In this chapter the construction of templates is not discussed (see chapter 18 for that). Rather, this chapter focuses on the use of these template algorithms.
Several parts of the standard template library have already been discussed in the C++ Annotations. In chapter 12 the abstract containers were discussed, and in section 9.10 function objects were introduced. Also, iterators were mentioned at several places in this document.
The remaining components of the STL will be covered in this chapter. Iterators, adaptors and generic algorithms will be discussed in the coming sections. Allocators take care of the memory allocation within the STL. The default allocator class suffices for most applications, and is not further discussed in the C++ Annotations.
Forgetting to delete
allocated memory is a common source of errors or
memory leaks in a program. The
auto_ptr template class may be used to
prevent these types of problems. The auto_ptr class is discussed in
section 17.3.
All elements of the STL are defined in the standard namespace. Therefore, a
using namespace std or comparable directive is required unless it is
preferred to specify the required namespace explicitly. This holds true in at
least one situation: in header files no using directive should be used,
so here the std:: scope specification should always be specified when
referring to elements of the STL.
sort()
expecting two iterators defining the range of objects that should be sorted,
as well as a function object calling the appropriate comparison operator for
two objects. Let's take a quick look at this situation. Assume strings are
stored in a vector, and we want to sort the vector in descending order. In
that case, sorting the vector stringVec is as simple as:
sort(stringVec.begin(), stringVec.end(), greater<std::string>());
The last argument is recognized as a
constructor: it is an
instantiation of the
greater<>() template class, applied to
strings. This object is called as a
function object by the sort()
generic algorithm. It will call the
operator>() of the provided data type
(here
std::string) wheneven its
operator()() is called. Eventually,
when sort() returns, the first element of the vector will be the greatest
element.
The operator()() (
function call operator) itself is not visible
at this point: don't confuse the parentheses in greater<string>() with
calling operator()(). When that operator is actually used inside
sort(), it receives two arguments: two strings to compare for
`greaterness'. Internally, the
operator>() of the data type to which the
iterators point (i.e., string) is called by greater<string>'s function
operator (operator()()) to compare the two objects. Since greater<>'s
function call operator is defined
inline, the call itself is not actually
present in the code. Rather, sort() calls string::operator>(),
thinking it called greater<>::operator()().
Now that we know that a constructor is passed as argument to (many) generic
algorithms, we can design our own function objects. Assume we want to sort our
vector case-insensitively. How do we proceed? First we note that the default
string::operator<() (for an incremental sort) is not appropriate, as it
does
case sensitive comparisons. So, we provide our own case_less
class, in which the two strings are compared case insensitively. Using the
standard C function
strcasecmp(), the following program performs the
trick. It sorts its command-line arguments in ascending alphabetical order:
#include <iostream>
#include <string>
#include <functional>
#include <algorithm>
using namespace std;
class case_less
{
public:
bool operator()(string const &left, string const &right) const
{
return strcasecmp(left.c_str(), right.c_str()) < 0;
}
};
int main(int argc, char **argv)
{
sort(argv, argv + argc, case_less());
for (int idx = 0; idx < argc; ++idx)
cout << argv[idx] << " ";
cout << endl;
}
The
default constructor of the class case_less is used with
sort()'s final argument. Therefore, the only member function that must be
defined with the class case_less is the function object operator
operator()(). Since we know it's called with string arguments, we
define it to expect two string arguments, which are used in the
strcasecmp() function. Furthermore, the operator()() function is made
inline, so that it does not produce overhead when called by the sort()
function. The sort() function calls the function object with various
combinations of strings, i.e., it thinks it does so. However, in fact
it calls strcasecmp(), due to the inline-nature of
case_less::operator()().
The comparison function object is often a predefined function object, since these are available for many commonly used operations. In the following sections the available predefined function objects are presented, together with some examples showing their use. At the end of the section about function objects function adaptors are introduced. Before predefined function objects can be used the following preprocessor directive must have been specified:
#include <functional>
Predefined function objects are used predominantly with generic
algorithms. Predefined function objects exists for arithmetic, relational, and
logical operations. In section 20.4 predefined function objects are
developed performing
bitwise operations.
plus<Type>
is available. If we set type to unsigned
then the + operator for unsigned values is used, if we set type to
string, then the + operator for strings is used. For example:
#include <iostream>
#include <string>
#include <functional>
using namespace std;
int main(int argc, char **argv)
{
plus<unsigned> uAdd; // function object to add unsigneds
cout << "3 + 5 = " << uAdd(3, 5) << endl;
plus<string> sAdd; // function object to add strings
cout << "argv[0] + argv[1] = " << sAdd(argv[0], argv[1]) << endl;
}
/*
Generated output with call: a.out going
3 + 5 = 8
argv[0] + argv[1] = a.outgoing
*/
Why is this useful? Note that the function object can be used with all
kinds of data types (not only with the predefined datatypes), in which the
particular operator has been overloaded. Assume that we want to perform an
operation on a common variable on the one hand and, on the other hand, in turn
on each element of an array. E.g., we want to compute the sum of the elements
of an array; or we want to concatenate all the strings in a text-array. In
situations like these the function objects come in handy. As noted before, the
function objects are heavily used in the context of the generic algorithms, so
let's take a quick look ahead at one of them.
One of the generic algorithms is called
accumulate(). It visits all
elements implied by an iterator-range, and performs a requested binary
operation on a common element and each of the elements in the range, returning
the accumulated result after visiting all elements.
For example, the following program accumulates all command line arguments,
and prints the final string:
#include <iostream>
#include <string>
#include <functional>
#include <numeric>
using namespace std;
int main(int argc, char **argv)
{
string result =
accumulate(argv, argv + argc, string(), plus<string>());
cout << "All concatenated arguments: " << result << endl;
}
The first two arguments define the (iterator) range of elements to visit,
the third argument is string(). This anonymous string object provides an
initial value. It could as well have been initialized to
string("All concatenated arguments: ")
in which case the cout statement could have been a simple
cout << result << endl
Then, the operator to apply is plus<string>(). Note here that a
constructor is called: it is not plus<string>, but rather
plus<string>(). The final concatenated string is returned.
Now we define our own class Time, in which the
operator+() has been overloaded. Again, we can apply the predefined
function object plus, now tailored to our newly defined datatype, to add
times:
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <functional>
#include <numeric>
using namespace std;
class Time
{
friend ostream &operator<<(ostream &str, Time const &time)
{
return cout << time.d_days << " days, " << time.d_hours <<
" hours, " <<
time.d_minutes << " minutes and " <<
time.d_seconds << " seconds.";
}
unsigned d_days;
unsigned d_hours;
unsigned d_minutes;
unsigned d_seconds;
public:
Time(unsigned hours, unsigned minutes, unsigned seconds)
:
d_days(0),
d_hours(hours),
d_minutes(minutes),
d_seconds(seconds)
{}
Time &operator+=(Time const &rValue)
{
d_seconds += rValue.d_seconds;
d_minutes += rValue.d_minutes + d_seconds / 60;
d_hours += rValue.d_hours + d_minutes / 60;
d_days += rValue.d_days + d_hours / 24;
d_seconds %= 60;
d_minutes %= 60;
d_hours %= 24;
return *this;
}
};
Time const operator+(Time const &lValue, Time const &rValue)
{
return Time(lValue) += rValue;
}
int main(int argc, char **argv)
{
vector<Time> tvector;
tvector.push_back(Time( 1, 10, 20));
tvector.push_back(Time(10, 30, 40));
tvector.push_back(Time(20, 50, 0));
tvector.push_back(Time(30, 20, 30));
cout <<
accumulate
(
tvector.begin(), tvector.end(), Time(0, 0, 0), plus<Time>()
) <<
endl;
}
/*
produced output:
2 days, 14 hours, 51 minutes and 30 seconds.
*/
Note that all member functions of Time in the above source are inline
functions. This approach was followed in order to keep the example relatively
small and to show explicitly that the operator+=() function may be an
inline function. On the other hand, in real life Time's operator+=()
should probably not be made inline, due to its size.
Considering the previous discussion of the plus function object, the
example is pretty straightforward. The class Time defines a constructor,
it defines an insertion operator and it defines its own operator+(),
adding two time objects.
In main() four Time objects are stored in a
vector<Time> object. Then, the accumulate() generic algorithm is
called to compute the accumulated time. It returns a Time object, which
is inserted in the cout ostream object.
While the first example did show the use of a named function object,
the last two examples showed the use of
anonymous objects which were
passed to the (accumulate()) function.
The following arithmetic objects are available as predefined objects:
plus<>(), as shown, this object's operator()() member calls
operator+() as a
binary operator, passing it its two parameters,
returning operator+()'s return value.
minus<>(), this object's operator()() member calls
operator-() as a binary operator, passing it its two parameters and
returning operator-()'s return value.
multiplies<>(), this object's operator()() member calls
operator*() as a binary operator, passing it its two parameters and
returning operator*()'s return value.
divides<>(), this object's operator()() member calls
operator/(), passing it its two parameters and
returning operator/()'s return value.
modulus<>(), this object's operator()() member calls
operator%(), passing it its two parameters and
returning operator%()'s return value.
negate<>(), this object's operator()() member calls
operator-() as a unary operator, passing it its parameter and
returning the unary operator-()'s return value.
operator-() follows, in
which the
transform() generic algorithm is used to toggle the signs of all
elements in an array. The transform() generic algorithm expects two
iterators, defining the range of objects to be transformed, an iterator
defining the begin of the destination range (which may be the same iterator as
the first argument) and a function object defining a unary operation for the
indicated data type.
#include <iostream>
#include <string>
#include <functional>
#include <algorithm>
using namespace std;
int main(int argc, char **argv)
{
int iArr[] = { 1, -2, 3, -4, 5, -6 };
transform(iArr, iArr + 6, iArr, negate<int>());
for (int idx = 0; idx < 6; ++idx)
cout << iArr[idx] << ", ";
cout << endl;
}
/*
Generated output:
-1, 2, -3, 4, -5, 6,
*/
==, !=, >, >=, < and <=. The
following objects are available:
equal_to<>(), this object's operator()() member calls
operator==() as a binary operator, passing it its two parameters and
returning operator==()'s return value.
not_equal_to<>(), this object's operator()() member calls
operator!=() as a binary operator, passing it its two parameters and
returning operator!=()'s return value.
greater<>(), this object's operator()() member calls
operator>() as a binary operator, passing it its two parameters and
returning operator>()'s return value.
greater_equal<>(), this object's operator()() member calls
operator>=() as a binary operator, passing it its two parameters and
returning operator>=()'s return value.
less<>(), this object's operator()() member calls
operator<() as a binary operator, passing it its two parameters and
returning operator<()'s return value.
less_equal<>(), this object's operator()() member calls
operator<=() as a binary operator, passing it its two parameters and
returning operator<=()'s return value.
sort() is:
#include <iostream>
#include <string>
#include <functional>
#include <algorithm>
using namespace std;
int main(int argc, char **argv)
{
sort(argv, argv + argc, greater_equal<string>());
for (int idx = 0; idx < argc; ++idx)
cout << argv[idx] << " ";
cout << endl;
sort(argv, argv + argc, less<string>());
for (int idx = 0; idx < argc; ++idx)
cout << argv[idx] << " ";
cout << endl;
}
The sort() generic algorithm expects an iterator range and a
comparator of the data type to which the iterators point. The example shows
the
alphabetic sorting of strings and the
reversed sorting of
strings. By passing greater_equal<string>() the strings are sorted in
decreasing order (the first word will be the 'greatest'), by passing
less<string>() the strings are sorted in increasing order (the first
word will be the 'smallest').
Note that the type of the elements of argv is char *, and that the
relational function object expects a string. The relational object
greater_equal<string>() will therefore use the >= operator of strings,
but will be called with char * variables. The promotion from char const
* to string is performed silently.
&&, || and !. The following objects are
available:
logical_and<>(), this object's operator()() member calls
operator&&() as a binary operator, passing it its two parameters and
returning operator&&()'s return value.
logical_or<>(), this object's operator()() member calls
operator||() as a binary operator, passing it its two parameters and
returning operator||()'s return value.
logical_not<>(), this object's operator()() member calls
operator!() as a unary operator, passing it its parameter and
returning the unary operator!()'s return value.
operator!() is provided in the following trivial
program, in which the
transform() generic algorithm is used to transform
the logical values stored in an array:
#include <iostream>
#include <string>
#include <functional>
#include <algorithm>
using namespace std;
int main(int argc, char **argv)
{
bool bArr[] = {true, true, true, false, false, false};
unsigned const bArrSize = sizeof(bArr) / sizeof(bool);
for (unsigned idx = 0; idx < bArrSize; ++idx)
cout << bArr[idx] << " ";
cout << endl;
transform(bArr, bArr + bArrSize, bArr, logical_not<bool>());
for (unsigned idx = 0; idx < bArrSize; ++idx)
cout << bArr[idx] << " ";
cout << endl;
}
/*
generated output:
1 1 1 0 0 0
0 0 0 1 1 1
*/
minus<int>() function object, which is a
binary function object, the
first argument may be bound to 100, meaning that the resulting value will
always be 100 minus the value of the second argument. Either the first or
the second argument may be bound to a specific value. To bind the first
argument to a specific value, the function object
bind1st() is used. To
bind the second argument of a binary function to a specific value
bind2nd() is used. As an example, assume we want to count all elements of
a vector of Person objects that exceed (according to some criterion) some
reference Person object. For this situation we pass the following binder
and
relational function object to the
count_if() generic algorithm:
bind2nd(greater<Person>(), referencePerson)
What would such a binder do? First of all, it's a function object, so it
needs operator()(). Next, it expects two arguments: a reference to another
function object and a fixed operand. Although binders are defined as
templates, it is illustrative to have a look at their implementations,
assuming they were straight functions. Here is such a pseudo-implementation of
a binder:
class bind2nd
{
FunctionObject const &d_object;
Operand const &d_rvalue;
public:
bind2nd(FunctionObject const &object, Operand const &operand)
:
d_object(object),
d_operand(operand)
{}
ReturnType operator()(Operand const &lvalue)
{
return d_object(lvalue, d_rvalue);
}
};
When its operator()() member is called the binder merely passes the
call to the object's operator()(), providing it with two arguments: the
lvalue it itself received and the fixed operand it received via its
constructor. Note the simplicity of these kind of classes: all its members can
usually be implemented inline.
The count_if() generic algorithm visits all the elements in an
iterator range, returning the number of times the
predicate specified as
its final argument returns
true. Each of the elements of the iterator
range is given to the predicate, which is therefore a
unary function. By
using the binder the binary function object greater() is adapted to a
unary function object, comparing each of the elements in the range to the
reference person. Here is, to be complete, the call of the count_if()
function:
count_if(pVector.begin(), pVector.end(),
bind2nd(greater<Person>(), referencePerson))
not1() is
the negator used with
unary function objects,
not2() is the
negator used with
binary function objects.
vector<Person> vector
not exceeding a certain reference person, we may, among other approaches,
use either of the following alternatives:
count_if(pVector.begin(), pVector.end(),
bind2nd(less_equal<Person>(), referencePerson))
not2 combined with the greater() predicate:
count_if(pVector.begin(), pVector.end(),
bind2nd(not2(greater<Person>()), referencePerson))
Note that not2() is a negator negating the truth value of a binary
operator()() member: it must be used to wrap the binary predicate
greater<Person>(), negating its truth value.
not1() combined with the bind2nd() predicate:
count_if(pVector.begin(), pVector.end(),
not1(bind2nd((greater<Person>()), referencePerson)))
Note that not1() is a negator negating the truth value of a unary
operator()() member: it is used to wrap the unary predicate bind2nd(),
negating its truth value.
The following little example illustrates the use of negator function adaptors, completing the section on function objects:
#include <iostream>
#include <functional>
#include <algorithm>
#include <vector>
using namespace std;
int main(int argc, char **argv)
{
int iArr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
cout << count_if(iArr, iArr + 10, bind2nd(less_equal<int>(), 6)) <<
endl;
cout << count_if(iArr, iArr + 10, bind2nd(not2(greater<int>()), 6)) <<
endl;
cout << count_if(iArr, iArr + 10, not1(bind2nd(greater<int>(), 6))) <<
endl;
}
/*
produced output:
6
6
6
*/
count_if():
operator()() is called;
<= is performed for int values.
not2 negator is used to
negate the truth value of the complementary logical function adaptor, three
actions must be performed for each iteration by count_if():
operator()() is called;
operator()() is called;
> is performed for int values.
not1 negator is used to
negate the truth value of the binder, three
actions must be performed for each iteration by count_if():
operator()() is called;
operator()() is called;
> is performed for int values.
g++ compiler on an old, 166 MHz pentium, performing 3.000.000
count_if() calls for each variant, shows the first approach requiring
about 70% of the time needed by the other two approaches to complete.
However, these differences disappear if the compiler is instructed to
optimize for speed (using the
-O6
compiler
flag). When interpreting these results one should keep in mind that multiple
nested function calls are merged into a single function call if the
implementations of these functions are given inline and if the compiler
follows the suggestion to implement these functions as true inline functions
indeed. If this is happening, the three approaches all merge to a single
operation: the comparison between two int values. It is likely that the
compiler does so when asked to optimize for speed.
== and
!= operators. Note that the ordering operators (e.g., >, <)
cannot normally be used.
iter, *iter represents the object the
iterator points to (alternatively, iter-> can be used to reach the members
of the object the iterator points to).
++iter or iter++ advances the iterator to the next
element. The notion of advancing an iterator to the next element is
consequently applied: several containers have a
reversed_iterator type, in
which the iter++ operation actually reaches a
previous element in a
sequence.
vector and
deque. For these containers iter + 2 points to the second element
beyond the one to which iter points.
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector<int>::iterator vi;
cout << &*vi << endl; // prints 0
}
iterator) using member functions
begin() and
end() and, in the
case of reversed iterators (type reverse_iterator),
rbegin() and
rend(). Standard practice requires the iterator range to be left
inclusive: the notation
[left, right) indicates that left is an
iterator pointing to the first element that is to be considered, while
right is an iterator pointing just beyond the last element to be
used. The iterator-range is said to be
empty when left == right.
Note that with
empty containers
the begin- and
end-iterators are equal to each other.
The following example shows a situation where all elements of a vector of
strings are written to cout using the iterator range
[begin(), end()), and the iterator range [rbegin(),
rend()). Note that the for-loops for both ranges are identical:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main(int argc, char **argv)
{
vector<string> args(argv, argv + argc);
for
(
vector<string>::iterator iter = args.begin();
iter != args.end();
++iter
)
cout << *iter << " ";
cout << endl;
for
(
vector<string>::reverse_iterator iter = args.rbegin();
iter != args.rend();
++iter
)
cout << *iter << " ";
cout << endl;
return 0;
}
Furthermore, the STL defines const_iterator types to be able to visit
a series of elements in a constant container. Whereas the elements of the
vector in the previous example could have been altered, the elements of the
vector in the next example are immutable, and const_iterators are
required:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main(int argc, char **argv)
{
vector<string> const args(argv, argv + argc);
for
(
vector<string>::const_iterator iter = args.begin();
iter != args.end();
++iter
)
cout << *iter << " ";
cout << endl;
for
(
vector<string>::const_reverse_iterator iter = args.rbegin();
iter != args.rend();
++iter
)
cout << *iter << " ";
cout << endl;
return 0;
}
The examples also illustrates that plain
pointers can be used instead of
iterators. The initialization vector<string> args(argv, argv + argc)
provides the args vector with a pair of pointer-based iterators: argv
points to the first element to initialize sarg with, argv + argc
points just beyond the last element to be used, argv++ reaches the next
string. This is a general characteristic of pointers, which is why they too
can be used in situations where iterators are expected.
The STL defines five types of iterators. These types recur in the generic algorithms, and in order to be able to create a particular type of iterator yourself it is important to know their characteristics. In general, iterators must define:
operator==(), testing two iterators for equality,
operator++(), incrementing the iterator, as
prefix operator,
operator*(), to access the element the iterator refers to,
InputIterators can read from a container. The dereference operator is guaranteed to work asrvaluein expressions. Instead of an InputIterator it is also possible to (see below) use a Forward-, Bidirectional- or RandomAccessIterator. With the generic algorithms presented in this chapter. Notations likeInputIterator1andInputIterator2may be observed as well. In these cases numbers are used to indicate which iterators `belong together'. E.g., the generic functioninner_product()has the following prototype:Type inner_product(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, Type init);HereInputIterator1 first1andInputIterator1 last1are a set of input iterators defining one range, whileInputIterator2 first2defines the beginning of a second range. Analogous notations like these may be observed with other iterator types.
OutputIterators can be used to write to a container. The dereference operator is guaranteed to work as anlvaluein expressions, but not necessarily asrvalue. Instead of an OutputIterator it is also possible to use, see below, a Forward-, Bidirectional- or RandomAccessIterator.
ForwardIterators combine InputIterators and OutputIterators. They can be used to traverse containers in one direction, for reading and/or writing. Instead of a ForwardIterator it is also possible to use a Bidirectional- or RandomAccessIterator.
BidirectionalIterators can be used to traverse containers in both directions, for reading and writing. Instead of a BidirectionalIterator it is also possible to use a RandomAccessIterator. For example, to traverse a list or a deque a BidirectionalIterator may be useful.
RandomAccessIterators provide
random access to container
elements. An algorithm such as
sort() requires a RandomAccessIterator, and
can therefore not be used with lists or maps, which only provide
BidirectionalIterators.
copy() algorithm
has three parameters, the first two defining the range of visited elements,
and the third parameter defines the first position where the results of the
copy operation should be stored. With the copy() algorithm the number of
elements that are copied are usually available beforehand, since the number is
usually determined using pointer arithmetic. However, there are situations
where pointer arithmetic cannot be used. Analogously, the number of resulting
elements sometimes differs from the number of elements in the initial
range. The generic algorithm unique_copy() is a case in
point: the number of elements which are copied to the destination container is
normally not known beforehand.
In situations like these, an
inserter adaptor function may be used to
create elements in the destination container when they are needed.
There are three types of inserter() adaptors:
back_inserter(): calls the container's
push_back() member to add
new elements at the end of the container. E.g., to copy all elements of
source in reversed order to the back of destination:
copy(source.rbegin(), source.rend(), back_inserter(destination));
front_inserter() calls the container's
push_front() member to add
new elements at the beginning of the container. E.g., to copy all elements of
source to the front of the destination container (thereby also reversing
the order of the elements):
copy(source.begin(), source.end(), front_inserter(destination));
inserter() calls the container's
insert() member to add new
elements starting at a specified starting point. E.g., to copy all elements of
source to the destination container, starting at the beginning of
destination, shifting existing elements beyond the newly inserted
elements:
copy(source.begin(), source.end(), inserter(destination,
destination.begin()));
back_inserter(), this iterator expects the name
of a container having a member push_back(). This member is called by the
inserter's operator()() member. When a class (other than the abstract
containers) supports a push_back() container, its objects can also be
used as arguments of the back_inserter() if the class defines a
typedef DataType const &const_reference;
in its interface, where DataType const & is the type of the parameter
of the class' member function push_back(). For example, the following
program defines a (compilable) skeleton of a class IntStore, whose objects
can be used as arguments of the back_inserter iterator:
#include <algorithm>
#include <iterator>
using namespace std;
class Y
{
public:
typedef int const &const_reference;
void push_back(int const &)
{}
};
int main()
{
int arr[] = {1};
Y y;
copy(arr, arr + 1, back_inserter(y));
}
istream_iterator<Type>() can be used to define an iterator (pair) for
istream objects. The general form of the istream_iterator<Type>()
iterator is:
istream_iterator<Type> identifier(istream &inStream)
Here, Type is the type of the data elements that are read from
the istream stream. Type may be any type for which operator>>() is
defined with istream objects.
The default constructor defines the end of the iterator pair, corresponding to end-of-stream. For example,
istream_iterator<string> endOfStream;
Note that the actual stream object which was specified for the
begin-iterator is not mentioned here.
Using a back_inserter() and a set of
istream_iterator<>() adaptors all strings could be read from cin as
follows:
#include <algorithm>
#include <iterator>
#include <string>
#include <vector>
using namespace std;
int main()
{
vector<string> vs;
copy(istream_iterator<string>(cin), istream_iterator<string>(),
back_inserter(vs));
for
(
vector<string>::iterator from = vs.begin();
from != vs.end();
++from
)
cout << *from << " ";
cout << endl;
return 0;
}
In the above example, note the use of the
anonymous versions of the
istream_iterator adaptors. Especially note the use of the anonymous
default constructor. Instead of using istream_iterator<string>() the
following (non-anonymous) construction could have been used:
istream_iterator<string> eos;
copy(istream_iterator<string>(cin), eos, back_inserter(vs));
Before istream_iterators can be used the following preprocessor
directive must have been specified:
#include <iterator>
This is implied when
iostream is included.
streambuf objects.
Before
istreambuf_iterators can be used the following preprocessor
directive must have been specified:
#include <iterator>
The
istreambuf_iterator is available for reading from streambuf
objects supporting
input operations. The standard operations
that are available for
istream_iterator objects are also available
for istreambuf_iterators. There are three
constructors:
istreambuf_iterator<Type>():This constructor represents the end-of-stream iterator while extracting values of typeTypefrom thestreambuf.
istreambuf_iterator<Type>(istream):This constructor constructs anistreambuf_iteratoraccessing thestreambufof theistreamobject, used as the constructor's argument.
istreambuf_iterator<Type>(streambuf *):This constructor constructs anistreambuf_iteratoraccessing thestreambufwhose address is used as the constructor's argument.
istreambuf_iterators and
ostreambuf_iterators.
ostream_iterator<Type>() can be used to define a destination iterator
for an
ostream object. The general forms
of the ostream_iterator<Type>() iterator are:
ostream_iterator<Type> identifier(ostream &outStream), // and:
ostream_iterator<Type> identifier(ostream &outStream, char const *delim);
Type is the type of the data elements that should be written to the
ostream stream. Type may be any type for which operator<<() is defined
in combinations with ostream objects. The latter form of the
ostream_iterators separates the individual Type data elements by
delimiter strings. The former definition does not use any delimiters.
The following example shows how
istream_iterators and an ostream_iterator may
be used to copy information of a file to another file. A subtlety is the
statement in.unsetf(ios::skipws): it resets the
ios::skipws flag. The
consequence of this is that the default behavior of operator>>(), to skip
whitespace, is modified. White space characters are simply returned by the
operator, and the file is copied unrestrictedly. Here is the program:
#include <algorithm>
#include <fstream>
#include <iomanip>
using namespace std;
int main(int argc, char **argv)
{
ifstream in(argv[1]);
ofstream out(argv[2]);
in.unsetf(ios::skipws);
copy(istream_iterator<char>(in), istream_iterator<char>(),
ostream_iterator<char>(out));
return 0;
}
Before ostream_iterators can be used the following preprocessor
directive must have been specified:
#include <iterator>
17.2.4.1: Iterators for `ostreambuf' objects
Before an
ostreambuf_iterator can be used the following preprocessor
directive must have been specified:
#include <iterator>
The
ostreambuf_iterator is available for writing to streambuf
objects supporting
output operations. The standard operations
that are available for
ostream_iterator objects are also available
for ostreambuf_iterators. There are two
constructors:
ostreambuf_iterator<Type>(ostream):This constructor constructs anostreambuf_iteratoraccessing thestreambufof theostreamobject, used as the constructor's argument, to insert values of typeType.
ostreambuf_iterator<Type>(streambuf *):This constructor constructs anostreambuf_iteratoraccessing thestreambufwhose address is used as the constructor's argument.
istreambuf_iterators and an ostreambuf_iterator, showing yet another
way to copy a stream:
#include <iostream>
#include <algorithm>
#include <iterator>
using namespace std;
int main()
{
istreambuf_iterator<char> in(cin.rdbuf());
istreambuf_iterator<char> eof;
ostreambuf_iterator<char> out(cout.rdbuf());
copy(in, eof, out);
return 0;
}
fun(), a memory leak is created by calling
fun(): the allocated int value remains inaccessibly allocated:
void fun()
{
new int;
}
To prevent memory leaks strict bookkeeping is required: the programmer has
to make sure that the memory pointed to by a pointer is deleted just before
the pointer variable goes
out of scope. In the above example the repair
would be:
void fun()
{
delete new int;
}
Now fun() only wastes a bit of time.
When a pointer variable points to a single value or object, the
bookkeeping requirements may be relaxed when the pointer variable is defined
as a std::auto_ptr
object. Auto_ptrs are objects,
masquerading as pointers. Since they're objects, their destructors are called
when they go out of scope, and because of that, their destructors will take
the responsibility of deleting the dynamically allocated memory.
Before auto_ptrs can be used the following preprocessor directive must
have been specified:
#include <memory>
Normally, an auto_ptr object is initialized using a dynamically
created value or object.
The following restrictions
apply to
auto_ptrs:
auto_ptr object cannot be used to point to
arrays of objects.
auto_ptr object should only point to memory that was made
available dynamically, as only
dynamically allocated memory can be deleted.
auto_ptr objects should not be allowed to point to the
same block of dynamically allocated memory. The auto_ptr's interface was
designed to prevent this from happening. Once an auto_ptr object goes out
of scope, it deletes the memory it points to, immediately changing any other
object also pointing at the allocated memory into a
wild
pointer.
class auto_ptr defines several member functions
to access the pointer itself or to have the auto_ptr point to another
block of memory. These member functions and ways to construct auto_ptr
objects are discussed in the next sections.
auto_ptr
objects. Each definition contains the usual <type> specifier between
pointed brackets. Concrete examples are given in the coming sections, but an
overview of the various possibilities is presented here:
auto_ptr object to point to a block
of memory allocated by the new operator:
auto_ptr<type> identifier (new-expression);
This form is discussed in section 17.3.2.
auto_ptr object using a copy
constructor:
auto_ptr<type> identifier(another auto_ptr for type);
This form is discussed in section 17.3.3.
auto_ptr object that
does not point to a particular block of memory:
auto_ptr<type> identifier;
This form is discussed in section 17.3.4.
auto_ptr
object is to provide its constructor with a block of memory allocated
by
operator new operator. The generic form is:
auto_ptr<type> identifier(new-expression);
For example, to initialize an auto_ptr to point to
a string object the
following construction can be used:
auto_ptr<string> strPtr(new string("Hello world"));
To initialize an auto_ptr to point to a double value the
following construction can be used:
auto_ptr<double> dPtr(new double(123.456));
Note the use of operator new in the above expressions. Using new
ensures the dynamic nature of the memory pointed to by the auto_ptr
objects and allows the deletion of the memory once auto_ptr objects go
out of scope. Also note that the type does not contain the pointer:
the
type used in the auto_ptr construction is
the same as used in the new expression.
In the example allocating an int values given in section 17.3,
the memory leak can be avoided using an auto_ptr object:
#include <memory>
using namespace std;
void fun()
{
auto_ptr<int> ip(new int);
}
All
member functions available for
objects allocated by the new expression can be reached via the
auto_ptr as if it was a plain pointer to the dynamically allocated
object. For example, in the following program the text `C++' is inserted
behind the word `hello':
#include <iostream>
#include <memory>
using namespace std;
int main()
{
auto_ptr<string> sp(new string("Hello world"));
cout << *sp << endl;
sp->insert(strlen("Hello "), "C++ ");
cout << *sp << endl;
}
/*
produced output:
Hello world
Hello C++ world
*/
auto_ptr
may also be initialized
by another auto_ptr object for the same type.
The generic form is:
auto_ptr<type> identifier(other auto_ptr object);
For example, to initialize an auto_ptr<string>, given the variable
sp defined in the previous section, the following construction can be
used:
auto_ptr<string> strPtr(sp);
Analogously, the assignment operator can
be used. An auto_ptr object may be assigned
to another auto_ptr object of the same type. For example:
#include <iostream>
#include <memory>
#include <string>
using namespace std;
int main()
{
auto_ptr<string> hello1(new string("Hello world"));
auto_ptr<string> hello2(hello1);
auto_ptr<string> hello3;
hello3 = hello2;
cout << *hello1 << endl <<
*hello2 << endl <<
*hello3 << endl;
}
/*
Produced output:
Segmentation fault
*/
Looking at the above example, we see that
hello1 is initialized as described in the previous section.
hello2 is defined, and it receives its value from
hello1, using a
copy constructor type of initialization. This
effectively changes hello1 into a 0-pointer.
hello3 is defined as a default auto_ptr<string>, but it
receives its value through an assignment from hello2, which then becomes a
0-pointer too.
hello3 actually points to a string.
auto_ptr object: Without arguments an empty auto_ptr object is
constructed not pointing to a particular block of memory:
auto_ptr<type> identifier;
In this case the
underlying pointer is set to
0 (zero). Since the auto_ptr object itself is not the pointer, its
value cannot be compared to 0 to see if it has not been initialized. E.g.,
code like
auto_ptr<int> ip;
if (!ip)
cout << "0-pointer with an auto_ptr object ?" << endl;
will not produce any output (actually, it won't compile either...). So,
how do we inspect the value of the pointer that's maintained by the
auto_ptr object? For this the member
get() is
available. This member function, as well as the other member functions of the
class auto_ptr are described in the next section.
auto_ptr:
auto_ptr &auto_ptr<Type>operator=(auto_ptr<Type> &other):This operator will transfer the memory pointed to by the rvalueauto_ptrobject to the lvalueauto_ptrobject. So, the rvalue object loses the memory it pointed at, and turns into a 0-pointer.
Type &auto_ptr<Type>operator*():This operator returns a reference to
the information stored in the auto_ptr object. It acts like a normal
pointer
dereference operator.
Type *auto_ptr<Type>operator->():This operator returns a pointer to the information stored in theauto_ptrobject. Through this operator members of a stored object an be selected. For example:auto_ptr<string> sp(new string("hello")); cout << sp->c_str() << endl;
auto_ptr objects:
Type *auto_ptr<Type>::get():This operator does the same asoperator->(): it returns a pointer to the information stored in theauto_ptrobject. This pointer can be inspected: if it's zero theauto_ptrobject does not point to any memory. This member cannot be used to let theauto_ptrobject point to (another) block of memory.
Type *auto_ptr<Type>::release():This operator returns a pointer to the information stored in theauto_ptrobject, which loses the memory it pointed at (and changes into a 0-pointer). The member can be used to transfer the information stored in theauto_ptrobject to a plainTypepointer. It is the responsibility of the programmer to delete the memory returned by this member function.
void auto_ptr<Type>::reset(Type *):This operator may also be called without argument, to delete the memory stored in theauto_ptrobject, or with a pointer to a dynamically allocated block of memory, which will thereupon be the memory accessed by theauto_ptrobject. This member function can be used to assign a new block of memory (new content) to anauto_ptrobject.
auto_ptr's main features have been described, consider
the following simple class:
// required #includes
class Map
{
std::map<string, Data> *d_map;
public:
Map(char const *filename) throw(std::exception);
};
The class' constructor Map() performs the following tasks:
std::map object;
Map::Map(char const *fname)
:
d_map(new std::map<std::string, Data>) throw(std::exception)
{
ifstream istr(fname);
if (!istr)
throw std::exception("can't open the file");
fillMap(istr);
}
What's wrong with this implementation? Its main weakness is that it hosts
a potential
memory leak. The memory leak only occurs when the exception is
actually thrown. In all other cases, the function operates perfectly
well. When the exception is thrown, the map has just been dynamically
allocated. However, even though the class' destructor will dutifully call
delete d_map, the destructor is actually never called, as the destructor
will only be called to destroy
objects that were constructed completely. Since the constructor terminates in
an exception, its associated object is not constructed completely, and
therefore that object's destructor is never called.
Auto_ptrs may be used to prevent these kinds of problems. By defining
d_map as
std::auto_ptr<std::map<std::string, Data> >
it suddenly changes into an object. Now, Map's constructor may safely
throw an exception. As d_map is an object itself, its destructor will be
called by the time the (however incompletely constructed) Map object goes
out of scope.
As a
rule of thumb: classes should use auto_ptr objects, rather
than plain pointers for their pointer data members if there's any chance that
their constructors will end prematurely in an exception.
Type is used to specify a
generic data type. Also, the particular type of iterator (see section
17.2) that is required is mentioned, as well as other generic types
that might be required (e.g., performing BinaryOperations, like
plus<Type>()).
Almost every generic algorithm expects an iterator range
[first, last),
defining the range of elements on which the algorithm operates. The iterators
point to objects or values. When an iterator points to a Type value or
object, function objects used by the algorithms usually receive Type const
& objects or values: function objects can therefore not modify the objects
they receive as their arguments. This does not hold true for
modifying generic algorithms, which are (of course) able to
modify the objects they operate upon.
Generic algorithms may be categorized. In the C++ Annotations the following categories of generic algorithms are distinguished:
Requires:#include <algorithm>equal(); includes(); lexicographical_compare(); max(); min(); mismatch();
Requires:#include <algorithm>copy(); copy_backward(); partial_sort_copy(); remove_copy(); remove_copy_if(); replace_copy(); replace_copy_if(); unique_copy();
Requires:
#include <algorithm>
Requires:
#include <algorithm>
Requires:
#include <algorithm>
Requires:#include <numeric>adjacent_difference(); accumulate(); inner_product(); partial_sum();
Requires:#include <algorithm>adjacent_find(); binary_search(); equal_range(); find(); find_if(); find_end(); find_first_of(); lower_bound(); max_element(); min_element(); search(); search_n(); set_difference(); set_intersection(); set_symmetric_difference(); set_union(); upper_bound();
Requires:#include <algorithm>inplace_merge(); iter_swap(); merge(); next_permutation(); nth_element(); partial_sort(); partial_sort_copy(); partition(); prev_permutation(); random_shuffle(); remove(); remove_copy(); remove_if(); remove_copy_if(); reverse(); reverse_copy(); rotate(); rotate_copy(); sort(); stable_partition(); stable_sort(); swap(); unique();
Requires:#include <algorithm>for_each(); replace(); replace_copy(); replace_if(); replace_copy_if(); transform(); unique_copy();
#include <numeric>
Type accumulate(InputIterator first, InputIterator last,
Type init);
Type accumulate(InputIterator first, InputIterator
last, Type init,BinaryOperation op);
operator+() is applied to all
elements implied by the iterator range and to the initial value init.
The resulting value is returned.
op() is applied to
all elements implied by the iterator range and to the initial value init,
and the resulting value is returned.
#include<numeric>
#include<vector>
#include<iostream>
using namespace std;
int main()
{
int ia[] = {1, 2, 3, 4};
vector<int> iv(ia, ia + 4);
cout <<
"Sum of values: " << accumulate(iv.begin(), iv.end(), int()) <<
endl <<
"Product of values: " << accumulate(iv.begin(), iv.end(), int(1),
multiplies<int>()) << endl;
return 0;
}
/*
Generated output:
Sum of values: 10
Product of values: 24
*/
#include <numeric>
OutputIterator adjacent_difference(InputIterator first,
InputIterator last,OutputIterator result);
OutputIterator adjacent_difference(InputIterator first,
InputIterator last,OutputIterator result, BinaryOperation op);
op applied to the
corresponding element in the input range (left operand) and its previous
element (right operand).
#include<numeric>
#include<vector>
#include<iostream>
using namespace std;
int main()
{
int ia[] = {1, 2, 5, 10};
vector<int> iv(ia, ia + 4);
vector<int> ov(iv.size());
adjacent_difference(iv.begin(), iv.end(), ov.begin());
copy(ov.begin(), ov.end(), ostream_iterator<int>(cout, " "));
cout << endl;
adjacent_difference(iv.begin(), iv.end(), ov.begin(), minus<int>());
copy(ov.begin(), ov.end(), ostream_iterator<int>(cout, " "));
cout << endl;
return 0;
}
/*
generated output:
1 1 3 5
1 1 3 5
*/
#include <algorithm>
ForwardIterator adjacent_find(ForwardIterator first,
ForwardIterator last);
OutputIterator adjacent_find(ForwardIterator first,
ForwardIterator last,Predicate pred);
last is returned.
pred returns true is returned. If no such element exists,
last is returned.
#include<algorithm>
#include<string>
#include<iostream>
class SquaresDiff
{
unsigned d_minimum;
public:
SquaresDiff(unsigned minimum)
:
d_minimum(minimum)
{}
bool operator()(unsigned first, unsigned second)
{
return second * second - first * first >= d_minimum;
}
};
using namespace std;
int main()
{
string sarr[] =
{
"Alpha", "bravo", "charley", "delta", "echo", "echo",
"foxtrot", "golf"
};
string *last = sarr + sizeof(sarr) / sizeof(string);
string *result = adjacent_find(sarr, last);
cout << *result << endl;
result = adjacent_find(++result, last);
cout << "Second time, starting from the next position:\n" <<
(
result == last ?
"** No more adjacent equal elements **"
:
"*result"
) << endl;
unsigned iv[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
unsigned *ilast = iv + sizeof(iv) / sizeof(unsigned);
unsigned *ires = adjacent_find(iv, ilast, SquaresDiff(10));
cout <<
"The first numbers for which the squares differ at least 10: "
<< *ires << " and " << *(ires + 1) << endl;
return 0;
}
/*
Generated output:
echo
Second time, starting from the next position:
** No more adjacent equal elements **
The first numbers for which the squares differ at least 10: 5 and 6
*/
#include <algorithm>
bool binary_search(ForwardIterator first,
ForwardIterator last,Type const &value);
bool binary_search(ForwardIterator first,
ForwardIterator last,Type const &value, Comparator comp);
value is looked up using binary
search in the range of elements implied by the iterator range [first,
last). The elements in the range must have been sorted by the
Type::operator<() function. True is returned if the element was found,
false otherwise.
value is looked up using binary
search in the range of elements implied by the iterator range [first,
last). The elements in the range must have been sorted by the
Comparator function object. True is returned if the element was found,
false otherwise.
#include <algorithm>
#include <string>
#include <iostream>
#include <functional>
using namespace std;
int main()
{
string sarr[] =
{
"alpha", "bravo", "charley", "delta", "echo",
"foxtrot", "golf", "hotel"
};
string *last = sarr + sizeof(sarr) / sizeof(string);
bool result = binary_search(sarr, last, "foxtrot");
cout << (result ? "found " : "didn't find ") << "foxtrot" << endl;
reverse(sarr, last); // reverse the order of elements
// binary search now fails:
result = binary_search(sarr, last, "foxtrot");
cout << (result ? "found " : "didn't find ") << "foxtrot" << endl;
// ok when using appropriate
// comparator:
result = binary_search(sarr, last, "foxtrot", greater<string>());
cout << (result ? "found " : "didn't find ") << "foxtrot" << endl;
return 0;
}
/*
Generated output:
found foxtrot
didn't find foxtrot
found foxtrot
*/
#include <algorithm>
OutputIterator copy(InputIterator first,
InputIterator last,OutputIterator destination);
[first, last) is copied to an output range, starting at
destination, using the assignment operator of the underlying data
type. The return value is the OutputIterator pointing just beyond the last
element that was copied to the destinatin range (so, `last' in the destination
range is returned).
copy(). It uses an ostream_iterator for
string objects. This iterator will write the string values to the
specified ostream (i.e., cout), separating the values by the specified
separation string (i.e., " ").
#include <algorithm>
#include <string>
#include <iostream>
#include <iterator>
using namespace std;
int main()
{
string sarr[] =
{
"alpha", "bravo", "charley", "delta", "echo",
"foxtrot", "golf", "hotel"
};
string *last = sarr + sizeof(sarr) / sizeof(string);
copy(sarr + 2, last, sarr); // move all elements two positions left
// copy to cout using an ostream_iterator
// for strings,
copy(sarr, last, ostream_iterator<string>(cout, " "));
cout << endl;
return 0;
}
/*
Generated output:
charley delta echo foxtrot golf hotel golf hotel
*/
unique_copy()
#include <algorithm>
BidirectionalIterator copy_backward(InputIterator first,
InputIterator last,BidirectionalIterator last2);
[first, last) are copied from the element at position last - 1
until (and including) the element at position first to the element range,
ending at position last2 - 1, using the assignment operator of the
underlying data type. The destination range is therefore [last2 - (last
- first), last2).
The return value is the BidirectionalIterator pointing at the last element that
was copied to the destinatin range (so, `first' in the destination range, pointed to by last2 - (last - first), is returned).
#include <algorithm>
#include <string>
#include <iostream>
#include <iterator>
using namespace std;
int main()
{
string sarr[] =
{
"alpha", "bravo", "charley", "delta", "echo",
"foxtrot", "golf", "hotel"
};
string *last = sarr + sizeof(sarr) / sizeof(string);
copy
(
copy_backward(sarr + 3, last, last - 3),
last,
ostream_iterator<string>(cout, " ")
);
cout << endl;
return 0;
}
/*
Generated output:
golf hotel foxtrot golf hotel foxtrot golf hotel
*/
#include <algorithm>
size_t count(InputIterator first, InputIterator last, Type
const &value);
value occurs in the
iterator range first, last is returned. To determine wheter value is
equal to an element in the iterator range Type::operator==() is used.
#include<algorithm>
#include<iostream>
using namespace std;
int main()
{
int ia[] = {1, 2, 3, 4, 3, 4, 2, 1, 3};
cout << "Number of times the value 3 is available: " <<
count(ia, ia + sizeof(ia) / sizeof(int), 3) <<
endl;
return 0;
}
/*
Generated output:
Number of times the value 3 is available: 3
*/
#include <algorithm>
size_t count_if(InputIterator first, InputIterator last,
Predicate predicate);
#include<algorithm>
#include<iostream>
class Odd
{
public:
bool operator()(int value)
{
return value & 1;
}
};
using namespace std;
int main()
{
int ia[] = {1, 2, 3, 4, 3, 4, 2, 1, 3};
cout << "The number of odd values in the array is: " <<
count_if(ia, ia + sizeof(ia) / sizeof(int), Odd()) << endl;
return 0;
}
/*
Generated output:
The number of odd values in the array is: 5
*/
#include <algorithm>
bool equal(InputIterator first, InputIterator last,
InputIterator otherFirst);
bool equal(InputIterator first, InputIterator last,
InputIterator otherFirst,BinaryPredicate pred);
[first,
last) are compared to a range of equal length starting at otherFirst. The
function returns true if the visited elements in both ranges are equal
pairwise. The ranges need not be of equal length, only the elements in the
indicated range are considered (and must be available).
[first, last) are compared to a range of equal length starting at
otherFirst. The function returns true if the binary predicate, applied
to all corresponding elements in both ranges returns true for every pair
of corresponding elements. The ranges need not be of equal length, only the
elements in the indicated range are considered (and must be available).
#include <algorithm>
#include <string>
#include <iostream>
class CaseString
{
public:
bool operator()(std::string const &first,
std::string const &second) const
{
return !strcasecmp(first.c_str(), second.c_str());
}
};
using namespace std;
int main()
{
string first[] =
{
"Alpha", "bravo", "Charley", "delta", "Echo",
"foxtrot", "Golf", "hotel"
};
string second[] =
{
"alpha", "bravo", "charley", "delta", "echo",
"foxtrot", "golf", "hotel"
};
string *last = first + sizeof(first) / sizeof(string);
cout << "The elements of `first' and `second' are pairwise " <<
(equal(first, last, second) ? "equal" : "not equal") <<
endl <<
"compared case-insensitively, they are " <<
(
equal(first, last, second, CaseString()) ?
"equal" : "not equal"
) << endl;
return 0;
}
/*
Generated output:
The elements of `first' and `second' are pairwise not equal
compared case-insensitively, they are equal
*/
#include <algorithm>
pair<ForwardIterator, ForwardIterator>
equal_range(ForwardIterator first,ForwardIterator last, Type const &value);
pair<ForwardIterator, ForwardIterator>
equal_range(ForwardIterator first,ForwardIterator last, Type const &value, Compare comp);
map (section 12.3.6) and multimap (section
12.3.7)):
operator<() of the data type to which the iterators point was used to
sort the elements in the provided range), a pair of iterators is returned
representing the return value of, respectively, lower_bound() (returning
the first element that is not smaller than the provided reference value, see
section 17.4.25) and upper_bound()(returning the first element
beyond the provided reference value, see section 17.4.66).
comp function object was used to sort the elements in the provided
range), a pair of iterators is returned representing the return value of,
respectively, lower_bound() (section 17.4.25) and
upper_bound()(section 17.4.66).
#include <algorithm>
#include <functional>
#include <iterator>
#include <iostream>
using namespace std;
int main()
{
int range[] = {1, 3, 5, 7, 7, 9, 9, 9};
unsigned const size = sizeof(range) / sizeof(int);
pair<int *, int *> pi;
pi = equal_range(range, range + size, 6);
cout << "Lower bound for 6: " << *pi.first << endl;
cout << "Upper bound for 6: " << *pi.second << endl;
pi = equal_range(range, range + size, 7);
cout << "Lower bound for 7: ";
copy(pi.first, range + size, ostream_iterator<int>(cout, " "));
cout << endl;
cout << "Upper bound for 7: ";
copy(pi.second, range + size, ostream_iterator<int>(cout, " "));
cout << endl;
sort(range, range + size, greater<int>());
cout << "Sorted in descending order\n";
copy(range, range + size, ostream_iterator<int>(cout, " "));
cout << endl;
pi = equal_range(range, range + size, 7, greater<int>());
cout << "Lower bound for 7: ";
copy(pi.first, range + size, ostream_iterator<int>(cout, " "));
cout << endl;
cout << "Upper bound for 7: ";
copy(pi.second, range + size, ostream_iterator<int>(cout, " "));
cout << endl;
return 0;
}
/*
Generated output:
Lower bound for 6: 7
Upper bound for 6: 7
Lower bound for 7: 7 7 9 9 9
Upper bound for 7: 9 9 9
Sorted in descending order
9 9 9 7 7 5 3 1
Lower bound for 7: 7 7 5 3 1
Upper bound for 7: 5 3 1
*/
#include <algorithm>
void fill(ForwardIterator first, ForwardIterator last, Type
const &value);
[first, last) are initialized to value, overwriting the previous
stored values.
#include<algorithm>
#include<vector>
#include<iterator>
#include<iostream>
using namespace std;
int main()
{
vector<int> iv(8);
fill(iv.begin(), iv.end(), 8);
copy(iv.begin(), iv.end(), ostream_iterator<int>(cout, " "));
cout << endl;
return 0;
}
/*
Generated output:
8 8 8 8 8 8 8 8
*/
#include <algorithm>
void fill_n(ForwardIterator first, Size n, Type
const &value);
n elements starting at the element pointed to by
first are initialized to value, overwriting the previous
stored values.
#include<algorithm>
#include<vector>
#include<iterator>
#include<iostream>
using namespace std;
int main()
{
vector<int> iv(8);
fill_n(iv.begin() + 2, 4, 8);
copy(iv.begin(), iv.end(), ostream_iterator<int>(cout, " "));
cout << endl;
return 0;
}
/*
Generated output:
0 0 8 8 8 8 0 0
*/
#include <algorithm>
InputIterator find(InputIterator first,
InputIterator last, Type const &value);
value is searched for in the range of the elements
implied by the iterator range [first, last). An iterator pointing to
the first element found is returned. If the element was not found, last is
returned. The operator==() of the underlying data type is used to
compare the elements.
#include<algorithm>
#include<string>
#include<iterator>
#include<iostream>
using namespace std;
int main()
{
string sarr[] =
{
"alpha", "bravo", "charley", "delta", "echo"
};
string *last = sarr + sizeof(sarr) / sizeof(string);
copy
(
find(sarr, last, "delta"), last, ostream_iterator<string>(cout, " ")
);
cout << endl;
if (find(sarr, last, "india") == last)
{
cout << "`india' was not found in the range\n";
copy(sarr, last, ostream_iterator<string>(cout, " "));
cout << endl;
}
return 0;
}
/*
Generated output:
delta echo
`india' was not found in the range
alpha bravo charley delta echo
*/
#include <algorithm>
ForwardIterator1 find_end(ForwardIterator1 first1,
ForwardIterator1 last1,ForwardIterator2 first2, ForwardIterator2 last2)
ForwardIterator1 find_end(ForwardIterator1 first1,
ForwardIterator1 last1,ForwardIterator2 first2, ForwardIterator2 last2,
BinaryPredicate pred)
[first1, last1) is searched for the last occurrence of the sequence of
elements implied by [first2, last2). If the sequence [first2,
last2) is not found, last1 is returned, otherwise an iterator pointing to
the first element of the matching sequence is returned. The operator==()
of the underlying data type is used to compare the elements in the two
sequences.
[first1, last1) is searched for the last occurrence of the sequence of
elements implied by [first2, last2). If the sequence [first2,
last2) is not found, last1 is returned, otherwise an iterator pointing to
the first element of the matching sequence is returned. The provided binary
predicate is used to compare the elements in the two sequences.
#include<algorithm>
#include<string>
#include<iterator>
#include<iostream>
class Twice
{
public:
bool operator()(unsigned first, unsigned second) const
{
return first == (second << 1);
}
};
using namespace std;
int main()
{
string sarr[] =
{
"alpha", "bravo", "charley", "delta", "echo",
"foxtrot", "golf", "hotel",
"foxtrot", "golf", "hotel",
"india", "juliet", "kilo"
};
string search[] =
{
"foxtrot",
"golf",
"hotel"
};
string *last = sarr + sizeof(sarr) / sizeof(string);
copy
(
find_end(sarr, last, search, search + 3), // sequence starting
last, ostream_iterator<string>(cout, " ") // at 2nd 'foxtrot'
);
cout << endl;
unsigned range[] = {2, 4, 6, 8, 10, 4, 6, 8, 10};
unsigned nrs[] = {2, 3, 4};
copy // sequence of values starting at last sequence
( // of range[] that are twice the values in nrs[]
find_end(range, range + 9, nrs, nrs + 3, Twice()),
range + 9, ostream_iterator<unsigned>(cout, " ")
);
cout << endl;
return 0;
}
/*
Generated output:
foxtrot golf hotel india juliet kilo
4 6 8 10
*/
#include <algorithm>
ForwardIterator1 find_first_of(ForwardIterator1 first1,
ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2)
ForwardIterator1 find_first_of(ForwardIterator1 first1,
ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2,
BinaryPredicate pred)
[first1, last1) is searched for the first occurrence of an element in
the sequence of elements implied by [first2, last2). If no element in
the sequence [first2, last2) is found, last1 is returned, otherwise
an iterator pointing to the first element in [first1, last1) that is
equal to an element in [first2, last2) is returned. The
operator==() of the underlying data type is used to compare the elements
in the two sequences.
[first1, first1) is searched for the first occurrence of an element in
the sequence of elements implied by [first2, last2). Each element in
the range [first1, last1) is compared to each element in the range
[first2, last2), and an iterator to the first element in
[first1, last1) for which the binary predicate pred (receiving an
the element out of the range [first1, last1) and an element from the
range [first2, last2)) returns true is returned. Otherwise,
last1 is returned.
#include<algorithm>
#include<string>
#include<iterator>
#include<iostream>
class Twice
{
public:
bool operator()(unsigned first, unsigned second) const
{
return first == (second << 1);
}
};
using namespace std;
int main()
{
string sarr[] =
{
"alpha", "bravo", "charley", "delta", "echo",
"foxtrot", "golf", "hotel",
"foxtrot", "golf", "hotel",
"india", "juliet", "kilo"
};
string search[] =
{
"foxtrot",
"golf",
"hotel"
};
string *last = sarr + sizeof(sarr) / sizeof(string);
copy
( // sequence starting
find_first_of(sarr, last, search, search + 3), // at 1st 'foxtrot'
last, ostream_iterator<string>(cout, " ")
);
cout << endl;
unsigned range[] = {2, 4, 6, 8, 10, 4, 6, 8, 10};
unsigned nrs[] = {2, 3, 4};
copy // sequence of values starting at first sequence
( // of range[] that are twice the values in nrs[]
find_first_of(range, range + 9, nrs, nrs + 3, Twice()),
range + 9, ostream_iterator<unsigned>(cout, " ")
);
cout << endl;
return 0;
}
/*
Generated output:
foxtrot golf hotel foxtrot golf hotel india juliet kilo
4 6 8 10 4 6 8 10
*/
#include <algorithm>
InputIterator find_if(InputIterator first,
InputIterator last, Predicate pred);
[first, last) for which the (unary)
predicate pred returns true is returned. If the element was not found,
last is returned.
#include<algorithm>
#include<string>
#include<iterator>
#include<iostream>
class CaseName
{
std::string d_string;
public:
CaseName(char const *str): d_string(str)
{}
bool operator()(std::string const &element)
{
return !strcasecmp(element.c_str(), d_string.c_str());
}
};
using namespace std;
int main()
{
string sarr[] =
{
"Alpha", "Bravo", "Charley", "Delta", "Echo",
};
string *last = sarr + sizeof(sarr) / sizeof(string);
copy
(
find_if(sarr, last, CaseName("charley")),
last, ostream_iterator<string>(cout, " ")
);
cout << endl;
if (find_if(sarr, last, CaseName("india")) == last)
{
cout << "`india' was not found in the range\n";
copy(sarr, last, ostream_iterator<string>(cout, " "));
cout << endl;
}
return 0;
}
/*
Generated output:
Charley Delta Echo
`india' was not found in the range
Alpha Bravo Charley Delta Echo
*/
#include <algorithm>
Function for_each(ForwardIterator first,
ForwardIterator last, Function func);
[first, last) is passed in turn as a reference to the function (or
function object) func. The function may modify the elements it receives
(as the used iterator is a forward iterator). Alternatively, if the elements
should be transformed, transform() (see section 17.4.63) can be
used. The function itself or a copy of the provided function object is
returned: see the example below, in which an extra argument list is added to
the for_each() call, which argument is eventually also passed to the
function given to for_each(). Within for_each() the return value of
the function that is passed to it is ignored.
#include<algorithm>
#include<string>
#include<iostream>
#include<cctype>
void lowerCase(char &c) // `c' *is* modified
{
c = static_cast<char>(tolower(c));
}
// `str' is *not* modified
void capitalizedOutput(std::string const &str)
{
char *tmp = strcpy(new char[str.size() + 1], str.c_str());
std::for_each(tmp + 1, tmp + str.size(), lowerCase);
tmp[0] = toupper(*tmp);
std::cout << tmp << " ";
delete tmp;
};
using namespace std;
int main()
{
string sarr[] =
{
"alpha", "BRAVO", "charley", "DELTA", "echo",
"FOXTROT", "golf", "HOTEL",
};
string *last = sarr + sizeof(sarr) / sizeof(string);
for_each(sarr, last, capitalizedOutput)("that's all, folks");
cout << endl;
return 0;
}
/*
Generated output:
Alpha Bravo Charley Delta Echo Foxtrot Golf Hotel That's all, folks
*/
#include<algorithm>
#include<string>
#include<iostream>
#include<cctype>
void lowerCase(char &c)
{
c = tolower(c);
}
class Show
{
int d_count;
public:
Show()
:
d_count(0)
{}
void operator()(std::string &str)
{
std::for_each(str.begin(), str.end(), lowerCase);
str[0] = toupper(str[0]); // here assuming str.length()
std::cout << ++d_count << " " << str << "; ";
}
int count() const
{
return d_count;
}
};
using namespace std;
int main()
{
string sarr[] =
{
"alpha", "BRAVO", "charley", "DELTA", "echo",
"FOXTROT", "golf", "HOTEL",
};
string *last = sarr + sizeof(sarr) / sizeof(string);
cout << for_each(sarr, last, Show()).count() << endl;
return 0;
}
/*
Generated output (all on a single line):
1 Alpha; 2 Bravo; 3 Charley; 4 Delta; 5 Echo; 6 Foxtrot;
7 Golf; 8 Hotel; 8
*/
for_each algorithm may be used with
functions defining const and non-const parameters. Also, see section
17.4.63 for differences between the for_each() and transform()
generic algorithms.
The for_each() algorithm cannot directly be used (i.e., by passing
*this as the function object argument) inside a member function to modify
its own object as the for_each() algorithm first creates it own copy of
the passed function object. A
wrapper class whose constructor accepts a
pointer or reference to the current object and possibly to one of its member
functions solves this problem. In section 20.7 the construction
of such wrapper classes is described.
#include <algorithm>
void generate(ForwardIterator first, ForwardIterator last,
Generator generator);
[first,
last) are initialized by the return value of generator, which can be a
function or function object. Note that Generator::opeator()() is not given
any arguments. The example uses a well-known fact from algebra: in order to
obtain the square of n + 1, add 1 + 2 * n to n * n.
#include<algorithm>
#include<vector>
#include<iterator>
#include<iostream>
class NaturalSquares
{
unsigned d_newsqr;
unsigned d_last;
public:
NaturalSquares(): d_newsqr(0), d_last(0)
{}
unsigned operator()()
{ // using: (a + 1)^2 == a^2 + 2*a + 1
return d_newsqr += (d_last++ << 1) + 1;
}
};
using namespace std;
int main()
{
vector<unsigned> uv(10);
generate(uv.begin(), uv.end(), NaturalSquares());
copy(uv.begin(), uv.end(), ostream_iterator<int>(cout, " "));
cout << endl;
return 0;
}
/*
Generated output:
1 4 9 16 25 36 49 64 81 100
*/
#include <algorithm>
void generate_n(ForwardIterator first, Size n,
Generator generator);
n elements starting at the element pointed to by
iterator first are initialized by the return value of generator,
which can be a function or function object.
#include<algorithm>
#include<vector>
#include<iterator>
#include<iostream>
class NaturalSquares
{
unsigned d_newsqr;
unsigned d_last;
public:
NaturalSquares(): d_newsqr(0), d_last(0)
{}
unsigned operator()()
{ // using: (a + 1)^2 == a^2 + 2*a + 1
return d_newsqr += (d_last++ << 1) + 1;
}
};
using namespace std;
int main()
{
vector<unsigned> uv(10);
generate_n(uv.begin(), 5, NaturalSquares());
copy(uv.begin(), uv.end(), ostream_iterator<int>(cout, " "));
cout << endl;
return 0;
}
/*
Generated output:
1 4 9 16 25 0 0 0 0 0
*/
#include <algorithm>
bool includes(InputIterator1 first1, InputIterator1 last1,
InputIterator2 first2, InputIterator2 last2);
bool includes(InputIterator1 first1, InputIterator1 last1,
InputIterator2 first2, InputIterator2 last2, Compare comp);
[first1, last1) and [first2, last2) should be sorted,
using the operator<() of the data type to which the iterators point. The
function returns true if every element in the second sequence
[first2, second2) is contained in the first sequence [first1,
second1) (the second range is a subset of the first range).
[first1, last1) and [first2, last2) should be sorted,
using the comp function object. The function returns true if every
element in the second sequence [first2, second2) is contained in the
first seqence [first1, second1) (the second range is a subset of the
first range).
#include <algorithm>
#include <string>
#include <iostream>
class CaseString
{
public:
bool operator()(std::string const &first,
std::string const &second) const
{
return (!strcasecmp(first.c_str(), second.c_str()));
}
};
using namespace std;
int main()
{
string first1[] =
{
"alpha", "bravo", "charley", "delta", "echo",
"foxtrot", "golf", "hotel"
};
string first2[] =
{
"Alpha", "bravo", "Charley", "delta", "Echo",
"foxtrot", "Golf", "hotel"
};
string second[] =
{
"charley", "foxtrot", "hotel"
};
unsigned n = sizeof(first1) / sizeof(string);
cout << "The elements of `second' are " <<
(includes(first1, first1 + n, second, second + 3) ? "" : "not")
<< " contained in the first sequence:\n"
"second is a subset of first1\n";
cout << "The elements of `first1' are " <<
(includes(second, second + 3, first1, first1 + n) ? "" : "not")
<< " contained in the second sequence\n";
cout << "The elements of `second' are " <<
(includes(first2, first2 + n, second, second + 3) ? "" : "not")
<< " contained in the first2 sequence\n";
cout << "Using case-insensitive comparison,\n"
"the elements of `second' are "
<<
(includes(first2, first2 + n, second, second + 3, CaseString()) ?
"" : "not")
<< " contained in the first2 sequence\n";
return 0;
}
/*
Generated output:
The elements of `second' are contained in the first sequence:
second is a subset of first1
The elements of `first1' are not contained in the second sequence
The elements of `second' are not contained in the first2 sequence
Using case-insensitive comparison,
the elements of `second' are contained in the first2 sequence
*/
#include <numeric>
Type inner_product(InputIterator1 first1,
InputIterator1 last1,InputIterator2 first2, Type init);
Type inner_product(InputIterator1 first1,
InputIterator1 last1,InputIterator2 first2, Type init, BinaryOperator1 op1,
BinaryOperator2 op2);
[first1, last1) and the same number of
elements starting at the element pointed to by first2
are added to init, and this sum is returned. The function uses the
operator+() and operator*() of the data type to which the iterators
point.
op2 instead of the
default addition operator, and binary operator op1 instead of the default
multiplication operator are applied to all pairwise elements implied by the
range [first1, last1) and the same number of elements starting at the
element pointed to by first2. The final result is returned.
#include <numeric>
#include <algorithm>
#include <iterator>
#include <iostream>
#include <string>
class Cat
{
std::string d_sep;
public:
Cat(std::string const &sep)
:
d_sep(sep)
{}
std::string operator()
(std::string const &s1, std::string const &s2) const
{
return s1 + d_sep + s2;
}
};
using namespace std;
int main()
{
unsigned ia1[] = {1, 2, 3, 4, 5, 6, 7};
unsigned ia2[] = {7, 6, 5, 4, 3, 2, 1};
unsigned init = 0;
cout << "The sum of all squares in ";
copy(ia1, ia1 + 7, ostream_iterator<unsigned>(cout, " "));
cout