7.11. Introduction to C++ Standard Library
Class Template vector
We now introduce C++ Standard Library class template vector, which
represents a more robust type of array featuring many additional capabilities.
As you'll see in later chapters, C-style pointer-based arrays (i.e., the type of
arrays presented thus far) have great potential for errors. For example, as
mentioned earlier, a program can easily "walk off" either end of an array,
because C++ does not check whether subscripts fall outside the range of an
array. Two arrays cannot be meaningfully compared with equality operators or
relational operators. As you'll see in Chapter
8, pointer variables (known more commonly as
pointers) contain memory addresses as their values. Array names are simply
pointers to where the arrays begin in memory, and, of course, two arrays will
always be at different memory locations. When an array is passed to a
general-purpose function designed to handle arrays of any size, the size of the
array must be passed as an additional argument. Furthermore, one array cannot be
assigned to another with the assignment operator(s)—array names are
const pointers, and, as you'll see in Chapter
8, a constant pointer cannot be used on the left
side of an assignment operator. These and other capabilities certainly seem like
"naturals" for dealing with arrays, but C++ does not provide such capabilities.
However, the C++ Standard Library provides class template vector to allow programmers to create a more powerful and
less error-prone alternative to arrays. In Chapter
11, Operator Overloading; String and Array Objects,
we present the means to implement such array capabilities as those provided by
vector. You'll see how to customize
operators for use with your own classes (a technique known as operator
overloading).
The vector class template
is available to anyone building applications with C++. The notations that the
vector example uses might be unfamiliar to
you, because vectors use template notation.
Recall that Section
6.18 discussed function templates. In Chapter
14, we discuss class templates. For now, you should
feel comfortable using class template vector
by mimicking the syntax in the example we show in this section. You'll deepen
your understanding as we study class templates in Chapter
14. Chapter
20 presents class template vector
(and several other standard C++ container classes) in detail.
The program of Fig. 7.26 demonstrates capabilities
provided by C++ Standard Library class template vector that are not
available for C-style pointer-based arrays. Standard class template
vector provides many of the same features as the Array class
that we construct in Chapter
11, Operator Overloading; String and Array Objects. Standard class template
vector is defined in header <vector> (line 11) and
belongs to namespace std (line 12). Chapter
20 discusses the full functionality of standard class template
vector.
Fig. 7.26. C++ Standard Library class template
vector.
1 // Fig. 7.26: fig07_26.cpp
2 // Demonstrating C++ Standard Library class template vector.
3 #include <iostream>
4 using std::cout;
5 using std::cin;
6 using std::endl;
7
8 #include <iomanip>
9 using std::setw;
10
11 #include <vector>
12 using std::vector;
13
14 void outputVector( const vector< int > & ); // display the vector
15 void inputVector( vector< int > & ); // input values into the vector
16
17 int main()
18 {
19 vector< int > integers1( 7 ); // 7-element vector< int >
20 vector< int > integers2( 10 ); // 10-element vector< int >
21
22 // print integers1 size and contents
23 cout << "Size of vector integers1 is " << integers1.size()
24 << "\nvector after initialization:" << endl;
25 outputVector( integers1 );
26
27 // print integers2 size and contents
28 cout << "\nSize of vector integers2 is " << integers2.size()
29 << "\nvector after initialization:" << endl;
30 outputVector( integers2 );
31
32 // input and print integers1 and integers2
33 cout << "\nEnter 17 integers:" << endl;
34 inputVector( integers1 );
35 inputVector( integers2 );
36
37 cout << "\nAfter input, the vectors contain:\n"
38 << "integers1:" << endl;
39 outputVector( integers1 );
40 cout << "integers2:" << endl;
41 outputVector( integers2 );
42
43 // use inequality (!=) operator with vector objects
44 cout << "\nEvaluating: integers1 != integers2" << endl;
45
46 if ( integers1 != integers2 )
47 cout << "integers1 and integers2 are not equal" << endl;
48
49 // create vector integers3 using integers1 as an
50 // initializer; print size and contents
51 vector< int > integers3( integers1 ); // copy constructor
52
53 cout << "\nSize of vector integers3 is " << integers3.size()
54 << "\nvector after initialization:" << endl;
55 outputVector( integers3 );
56
57 // use overloaded assignment (=) operator
58 cout << "\nAssigning integers2 to integers1:" << endl;
59 integers1 = integers2; // assign integers2 to integers1
60
61 cout << "integers1:" << endl;
62 outputVector( integers1 );
63 cout << "integers2:" << endl;
64 outputVector( integers2 );
65
66 // use equality (==) operator with vector objects
67 cout << "\nEvaluating: integers1 == integers2" << endl;
68
69 if ( integers1 == integers2 )
70 cout << "integers1 and integers2 are equal" << endl;
71
72 // use square brackets to create rvalue
73 cout << "\nintegers1[5] is " << integers1[ 5 ];
74
75 // use square brackets to create lvalue
76 cout << "\n\nAssigning 1000 to integers1[5]" << endl;
77 integers1[ 5 ] = 1000;
78 cout << "integers1:" << endl;
79 outputVector( integers1 );
80
81 // attempt to use out-of-range subscript
82 cout << "\nAttempt to assign 1000 to integers1.at( 15 )" << endl;
83 integers1.at( 15 ) = 1000; // ERROR: out of range
84 return 0;
85 } // end main
86
87 // output vector contents
88 void outputVector( const vector< int > &array )
89 {
90 size_t i; // declare control variable
91
92 for ( i = 0; i < array.size(); i++ )
93 {
94 cout << setw( 12 ) << array[ i ];
95
96 if ( ( i + 1 ) % 4 == 0 ) // 4 numbers per row of output
97 cout << endl;
98 } // end for
99
100 if ( i % 4 != 0 )
101 cout << endl;
102 } // end function outputVector
103
104 // input vector contents
105 void inputVector( vector< int > &array )
106 {
107 for ( size_t i = 0; i < array.size(); i++ )
108 cin >> array[ i ];
109 } // end function inputVector
|
Size of vector integers1 is 7
vector after initialization:
0 0 0 0
0 0 0
Size of vector integers2 is 10
vector after initialization:
0 0 0 0
0 0 0 0
0 0
Enter 17 integers:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
After input, the vectors contain:
integers1:
1 2 3 4
5 6 7
integers2:
8 9 10 11
12 13 14 15
16 17
Evaluating: integers1 != integers2
integers1 and integers2 are not equal
Size of vector integers3 is 7
vector after initialization:
1 2 3 4
5 6 7
Assigning integers2 to integers1:
integers1:
8 9 10 11
12 13 14 15
16 17
integers2:
8 9 10 11
12 13 14 15
16 17
Evaluating: integers1 == integers2
integers1 and integers2 are equal
integers1[5] is 13
Assigning 1000 to integers1[5]
integers1:
8 9 10 11
12 1000 14 15
16 17
Attempt to assign 1000 to integers1.at( 15 )
abnormal program termination
|
Lines 19–20 create two vector objects that store
values of type int—integers1 contains seven elements, and
integers2 contains 10 elements. By default, all the elements of each
vector object are set to 0. Note that vectors can be defined to store any data type, by replacing int in
vector< int > with the appropriate data
type. This notation, which specifies the type stored in the vector, is similar to the template notation that Section
6.18 introduced with function templates. Again, Chapter
14 discusses this syntax in detail.
Line 23 uses vector member
function size to obtain the size
(i.e., the number of elements) of integers1. Line 25 passes
integers1 to function outputVector (lines 88–102), which uses square brackets, [] (line 94), to obtain
the value in each element of the vector for
output. Note the resemblance of this notation to that used to access the value
of an array element. Lines 28 and 30 perform the same tasks for
integers2.
Member function size of
class template vector returns the number of
elements in a vector as a value of type
size_t (which represents the type unsigned
int on many systems). As a result, line 90 declares
the control variable i to be of type size_t, too. On some
compilers, declaring i as an int
causes the compiler to issue a warning message, since the loop-continuation
condition (line 92) would compare a signed value (i.e., int i)
and an unsigned value (i.e., a value of type size_t returned
by function size).
Lines 34–35 pass integers1 and integers2 to
function inputVector (lines 105–109) to read values for each
vector's elements from the user. The function
uses square brackets ([]) to form lvalues that are used to store
the input values in each vector element.
Line 46 demonstrates that vector objects can be
compared with one another using the != operator. If the contents of two
vectors are not equal, the operator returns true; otherwise,
it returns false.
The C++ Standard Library class template vector allows
you to create a new vector object that is initialized with the contents
of an existing vector. Line 51 creates a vector object
integers3 and initializes it with a copy of integers1. This
invokes vector's so-called copy constructor to
perform the copy operation. You'll learn about copy constructors in detail in Chapter
11. Lines 53–55 output the size and contents of
integers3 to demonstrate that it was initialized
correctly.
Line 59 assigns integers2 to integers1, demonstrating that the assignment (=) operator can be used with vector objects. Lines 61–64 output the contents of both objects
to show that they now contain identical values. Line 69 then compares
integers1 to integers2 with the equality (==) operator to determine whether the contents of the two
objects are equal after the assignment in line 59 (which they are).
Lines 73 and 77 demonstrate that a
program can use square brackets ([]) to obtain a vector
element as an rvalue and as an lvalue, respectively. Recall from Section
5.9 that an rvalue cannot be modified, but an
lvalue can. As is the case
with C-style pointer-based arrays, C++ does not perform any bounds checking when
vector elements are accessed with square brackets.
Therefore, you must ensure that operations using [] do not accidentally attempt to manipulate elements outside
the bounds of the vector. Standard class template vector does, however, provide bounds checking in its member function
at, which "throws an exception"
(see Chapter
16, Exception Handling) if its argument is an
invalid subscript. By default, this causes a C++ program to terminate. If the
subscript is valid, function at returns the
element at the specified location as a modifiable lvalue or an unmodifiable lvalue, depending on the context
(non-const or const) in which the call appears.
Line 83 demonstrates a call to function at
with an invalid subscript. The resulting output varies by compiler.
In this section, we demonstrated the C++
Standard Library class template vector, a robust, reusable class that
can replace C-style pointer-based arrays. In Chapter
11, you'll see that vector
achieves many of its capabilities by "overloading" C++'s built-in operators, and
you'll see how to customize operators for use with your own classes in similar
ways. For example, we create an Array class
that, like class template vector,
improves upon basic array capabilities. Our Array class also provides additional features, such as
the ability to input and output entire arrays with operators >>
and <<, respectively.