7.10 Introduction to C++ Standard Library Class Template vector

We now introduce C++ Standard Library class template vector, which is similar to class template array, but also supports dynamic resizing. Except for the features that modify a vector, the other features shown in Fig. 7.21 also work for arrays. Standard class template vector is defined in header <vector> (line 5) and belongs to namespace std. Chapter 15 discusses the full functionality of vector. At the end of this section, we’ll demonstrate class vector’s bounds checking capabilities and introduce C++’s exception-handling mechanism, which can be used to detect and handle an out-of-bounds vector index.

Fig. 7.21 Demonstrating C++ Standard Library class template vector.

Alternate View

 1   // Fig. 7.21: fig07_21.cpp
 2   // Demonstrating C++ Standard Library class template vector.
 3   #include <iostream>
 4   #include <iomanip>
 5   #include <vector>   
 6   #include <stdexcept>
 7   using namespace std;
 8
 9   void outputVector(const vector<int>&); // display the vector
10   void inputVector(vector<int>&); // input values into the vector
11
12   int main() {
13      vector<int> integers1{7}; // 7-element vector<int>  
14      vector<int> integers2(10); // 10-element vector<int>
15
16      // print integers1 size and contents
17      cout << "Size of vector integers1 is " << integers1.size()
18         << "
vector after initialization:";
19      outputVector(integers1);
20
21      // print integers2 size and contents
22      cout << "
Size of vector integers2 is " << integers2.size()
23         << "
vector after initialization:";
24      outputVector(integers2);
25
26      // input and print integers1 and integers2
27      cout << "
Enter 17 integers:" << endl;
28      inputVector(integers1);
29      inputVector(integers2);
30
31      cout << "
After input, the vectors contain:
"
32         << "integers1:";
33      outputVector(integers1);
34      cout << "integers2:";
35      outputVector(integers2);
36
37      // use inequality (!=) operator with vector objects
38      cout << "
Evaluating: integers1 != integers2" << endl;
39
40      if (integers1 != integers2) {
41         cout << "integers1 and integers2 are not equal" << endl;
42      }
43
44      // create vector integers3 using integers1 as an
45      // initializer; print size and contents
46      vector<int> integers3{integers1}; // copy constructor
47
48      cout << "
Size of vector integers3 is " << integers3.size()
49         << "
vector after initialization: ";
50      outputVector(integers3);
51
52      // use overloaded assignment (=) operator              
53      cout << "
Assigning integers2 to integers1:" << endl; 
54      integers1 = integers2; // assign integers2 to integers1
55
56      cout << "integers1: ";
57      outputVector(integers1);
58      cout << "integers2: ";
59      outputVector(integers2);
60
61      // use equality (==) operator with vector objects
62      cout << "
Evaluating: integers1 == integers2" << endl;
63
64      if (integers1 == integers2) {
65         cout << "integers1 and integers2 are equal" << endl;
66      }
67
68      // use square brackets to use the value at location 5 as an rvalue
69      cout << "
integers1[5] is " << integers1[5];
70
71       // use square brackets to create lvalue
72       cout << "

Assigning 1000 to integers1[5]" << endl;
73       integers1[5] = 1000;
74       cout << "integers1: ";
75       outputVector(integers1);
76
77       // attempt to use out-of-range subscript                   
78       try {                                                      
79          cout << "
Attempt to display integers1.at(15)" << endl;
80          cout << integers1.at(15) << endl; // ERROR: out of range
81       }                                                          
82       catch (out_of_range& ex) {                                 
83          cerr << "An exception occurred: " << ex.what() << endl; 
84       }                                                          
85
86       // changing the size of a vector
87       cout << "
Current integers3 size is: " << integers3.size() << endl;
88       integers3.push_back(1000); // add 1000 to the end of the vector
89       cout << "New integers3 size is: " << integers3.size() << endl;
90       cout << "integers3 now contains: ";
91       outputVector(integers3);
92    }
93
94    // output vector contents
95    void outputVector(const vector<int>& items) {
96       for (int item : items) {
97          cout << item << " ";
98       }
99
100      cout << endl;
101   }
102
103   // input vector contents
104   void inputVector(vector<int>& items) {
105      for (int& item : items) {
106         cin >> item;
107      }
108   }

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 display integers1.at(15)
An exception occurred: invalid vector<T> subscript

Current integers3 size is: 7
New integers3 size is: 8
integers3 now contains: 1 2 3 4 5 6 7 1000

Creating vector Objects

Lines 13–14 create two vector objects that store values of type intintegers1 contains seven elements, and integers2 contains 10 elements. By default, all the elements of each vector object are set to 0. Like arrays, vectors can be defined to store most data types, by replacing int in vector<int> with the appropriate type.

Notice that we used parentheses rather than braces to pass the size argument to each vector object’s constructor. When creating a vector, if the braces contain one value of the vector’s element type, the braces are treated as a one-element initializer list, rather than a call to the constructor that sets the vector’s size. So the following declaration


vector<int> integers1{7};

actually creates a one-element vector<int> containing the int value 7, not a 7-element vector.

vector Member Function size; Function outputVector

Line 17 uses vector member function size to obtain the size (i.e., the number of elements) of integers1. Line 19 passes integers1 to function outputVector (lines 95–101), which uses a range-based for statement to obtain the value in each element of the vector for output. As with class template array, you can also do this using a counter-controlled loop and the subscript ([]) operator. Lines 22 and 24 perform the same tasks for integers2.

Function inputVector

Lines 28–29 pass integers1 and integers2 to function inputVector (lines 104–108) to read values for each vector’s elements from the user. The function uses a range-based for statement with a range variable that’s a reference to an int. Because the range variable is a reference to a vector element, the reference can be used t store a input value in the corresponding element.

Comparing vector Objects for Inequality

Line 40 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.

Initializing One vector with the Contents of Another

The C++ Standard Library class template vector allows you to create a new vector object that’s initialized with the contents of an existing vector. Line 46 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 10. Lines 48–50 output the size and contents of integers3 to demonstrate that it was initialized correctly.

Assigning vectors and Comparing vectors for Equality

Line 54 assigns integers2 to integers1, demonstrating that the assignment (=) operator can be used with vector objects. Lines 56–59 output the contents of both objects to show that they now contain identical values. Line 64 then compares integers1 to integers2 with the equality (==) operator to determine whether the contents of the two objects are equal (which they are) after the assignment in line 54.

Using the [] Operator to Access and Modify vector Elements

Lines 69 and 73 use square brackets ([]) to obtain a vector element and use it as an rvalue and as an lvalue, respectively. Recall from Section 5.12 that an rvalue cannot be modified, but an lvalue can. As is the case with arrays, C++ is not required to perform bounds checking when vector elements are accessed with square brackets.2 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 (as does class template array), which we use at line 80 and discuss shortly.

Exception Handling: Processing an Out-of-Range Subscript

An exception indicates a problem that occurs while a program executes. The name “exception” suggests that the problem occurs infrequently. Exception handling enables you to create fault-tolerant programs that can process (or handle) exceptions. In many cases, this allows a program to continue executing as if no problems were encountered. For example, Fig. 7.21 still runs to completion, even though an attempt was made to access an out-of-range subscript. More severe problems might prevent a program from continuing normal execution, instead requiring the program to notify the user of the problem, then terminate. When a function detects a problem, such as an invalid array subscript or an invalid argument, it throws an exception—that is, an exception occurs. Here we introduce exception handling briefly. We’ll discuss it in detail in Chapter 17.

The try Statement

To handle an exception, place any code that might throw an exception in a try statement (lines 78–84). The try block (lines 78–81) contains the code that might throw an exception, and the catch block (lines 82–84) contains the code that handles the exception if one occurs. As you’ll see in Chapter 17, you can have many catch blocks to handle different types of exceptions that might be thrown in the corresponding try block. If the code in the try block executes successfully, lines 82–84 are ignored. The braces that delimit try and catch blocks’ bodies are required.

The vector member function at provides bounds checking and throws an exception if its argument is an invalid subscript. By default, this causes a C++ program to terminate. If the subscript is valid, function at returns either

  • a reference to the element at that location—this is a modifiable lvalue that can be used to change the value of the corresponding vector element, or

  • a const reference to the element at that location—this is a nonmodifiable lvalue that cannot be used to change the value of the corresponding vector element.

A nonmodifiable lvalue is treated as a const object. If at is called on a const array or via a reference that’s declared const, the function returns a const reference.

Executing the catch Block

When the program calls vector member function at with the argument 15 (line 80), the function attempts to access the element at location 15, which is outside the vector’s bounds—integers1 has only 10 elements at this point. Because bounds checking is performed at execution time, vector member function at generates an exception—specifically line 80 throws an out_of_range exception (from header <stdexcept>) to notify the program of this problem. At this point, the try block terminates immediately and the catch block begins executing—if you declared any variables in the try block, they’re now out of scope and are not accessible in the catch block.

The catch block declares a type (out_of_range) and an exception parameter (ex) that it receives as a reference. The catch block can handle exceptions of the specified type. Inside the block, you can use the parameter’s identifier to interact with a caught exception object.

Performance Tip 7.2

Catching an exception by reference increases performance by preventing the exception object from being copied when it’s caught. You’ll see in later chapters that catching by reference is also important when defining catch blocks that process related exception types.

what Member Function of the Exception Parameter

When lines 82–84 catch the exception, the program displays a message indicating the problem that occurred. Line 83 calls the exception object’s what member function to get the error message that’s stored in the exception object and display it. Once the message is displayed in this example, the exception is considered handled and the program continues with the next statement after the catch block’s closing brace. In this example, lines 87–91 execute next. We use exception handling again in Chapters 912 and Chapter 17 presents a deeper look.

Changing the Size of a vector

One of the key differences between a vector and an array is that a vector can dynamically grow and shrink as the number of elements it needs to accommodate varies. To demonstrate this, line 87 shows the current size of integers3, line 88 calls the vector’s push_back member function to add a new element containing 1000 to the end of the vector and line 89 shows the new size of integers3. Line 91 then displays integers3’s new contents.

C++11: List Initializing a vector

Many of the array examples in this chapter used list initializers to specify the initial array element values. C++11 also allows this for vectors (and other C++ Standard Library data structures).

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset