Name: _____________________ Class: CET 375
SSN/ID:   _____________________ Section & Group: ____________
The vectors Tutorial


A. Introduction

Lab Exercise 5 dealt with C-style arrays, which are very non-OOPish in that they are not self-contained; that is, they are not objects that carry around with them information about themselves or operations on themselves. This is surely the case for non-char arrays for which there are very few predefined array operations. For example, an array does not keep track of the number of values currently stored in it (its size).

This lab exercise considers in detail the vector container from STL (the Standard Template Library), which is an OOP counterpart to one-dimensional arrays. It can be thought of as a type-independent pattern for an array class whose capacity can expand and which is self-contained. More precisely, vector is a class template that can be used to store and process elements of any type. A vector can expand its capacity when necessary. And a vector has a large collection of built-in operations that are implemented as function members. Its declaration has the form:

template <typename T>
class vector {
  // Details of vector omitted...
};
where T is a parameter for the type of values to be stored in the container.

Example:

vector<double> vec1; vector<string> names;
Compiler
Compiler
Creates definition of class vector with each occurence of T replaced by double; uses this class to construct object named vec1 Creates definition of class vector with each occurence of T replaced by string; uses this class to construct object named names

Note: In this lab exercise, you will use the program source_lab07_vectorlab.cpp to experiment with vectors. Get a copy of this program by right-clicking the link and copying/saving it to your home directory and then rename it to vectorlab.cpp.

B. Defining a vector Object

vector has 4 constructors (and a copy constructor) which allow 4 different kinds of definitions of vector objects:

  1. vector<element_type> object_name;
  2. vector<element_type> object_name(initial_capacity);
  3. vector<element_type> object_name(initial_capacity, initial_value);
  4. vector<element_type> object_name(first_ptr, last_ptr);
    where first_ptr and last_ptr are pointers to (addresses of) array elements.

Examples (from vectorlab.cpp):

vector<int> v1;

vector<int> v2(2);

int numInts;
cin >> numInts;
vector<int> v3(numInts);

vector<int> v4(3, 99);

int a[] = (1, 4, 9, 16, 25);
vector<int> v5(a, a+5);

C. Member Functions dealing with capacity and size

v.empty() Return true if and only if v contains no values
v.size() Return the number of values v contains
v.capacity() Return the capacity of v; that is, the number of values it currently can store
v.max_size() Return the maximum number of elements v can have (i.e., max. capacity)
v.reserve(n) Increase capacity of v to n (does not affect size())

  1. In the section of vectorlab.cpp labelled //--- 1 ---, add statements to display the capacity and size of each of v1, v2, v3, v4, and v5 and whether each is empty. Record the results here:

    vector capacity size_of empty (Y or N)
    v1      
    v2      
    v3      
    v4      
    v5      

  2. The maximum capacity of a vector is machine dependent. In the section of vectorlabp.cpp labelled //--- 2 ---, add a statement to determine the maximum capacity of v1 for our system and record this value here: ____________________
  3. In section 3 of the program, add the statement v4.reserve(7); and an output statement to display its capacity and size. Record them here:

    vector capacity size_of
    v4    

  4. The output operator has been overloaded in vectorlab.cpp so it can be used to output vector<T>s. In section 4, add output statements to display each of v1, v2, v3, v4, and v5 and record the contents of each here:
        v1: ___________________________________________________________
    
        v2: ___________________________________________________________
    
        v3: ___________________________________________________________
    
        v4: ___________________________________________________________
    
        v5: ___________________________________________________________
        
    As you can see from the preceding:

D. Member Functions to append and remove values

v.push_back(value); Append value at v's end and increase v's size by 1
v.pop_back(); Erase v's last element and decrease v's size by 1

  1. In section 5 of vectorlab.cpp, add statements to append 11 to v2, and then output the size and contents of v2. Record the results here:

    vector size contents
    v2    

    Add statements to append 22 to v2, and then output the size and contents of v2. Record the results here:

    vector size contents
    v2    

    Add statements to append 33 to v2, and then output the size and contents of v2. Record the results here:

    vector size contents
    v2    

    Now, add statements to erase the last element of v2, and then output the size and contents of v2. Record the results here:

    vector size contents
    v2    

    Note how each push_back() and pop_back() operation updates the size of the vector.

E. A Fundamental Difference between vectors and Arrays

We have seen several differences between vectors and arrays. In particular, we have examined several of the built-in operations that vectors have but that arrays do not.

The preceding examples also indicate another basic difference between vectors and arrays. Even though the original capacity of v2 was 2, we were able to append 3 new values to v2 and its size increased each time. This would also suggest that its capacity increased.

And this is indeed the case. Although the capacity of an array is fixed, the capacity of a vector is increased automatically when necessary to accomodate a new value being appended. This is accomplished by allocating a larger block of memory (array) and copying the current values into it. The actual amount by which the capacity is increased is machine-dependent, but there are some patterns that are common to all implementations. We will investigate some of these now.

  1. Obviously, for empty vectors like v1, the capacity will have to be increased when the first value is appended. In Section 6 of vectorlab.cpp, add a statement to append 111 to v1 and then output its capacity, size, and contents. Then, compile and execute the program. Record the results here:

    v1 after: capacity size contents
    1 value is added      

  2. Now, let's see what happens if we continue to add values to v1. In Section 7 of vectorlab.cpp, add statements to append 222, 333, 444, and 555 to v1 and to output its capacity, size, and contents after each value is appended. Then, compile and execute the program. Record the results here:

    v1 after: capacity size contents
    1 value is added      
    2 values are added      
    3 values are added      
    4 values are added      
    5 values are added      

    What seems to be the pattern in how the capacity is increasing?






  3. To check your answer to the preceding question, remove the comments in Section 8 of vectorlab.cpp, and compile and execute the program. This code adds 2495 more values to v1 and displays capacity changes. Record the capacity changes in the following table:

    v1's old capacity v1's new capacity
       
       
       
       
       
       
       
       

  4. Determine whether the increases in capacity depend on the type of elements in the vector by adding in Section 9 of vectorlab.cpp a declaration vector<double> vv; and a loop similar to that in Section 8 but that runs from i=1 to i=2500. Then, change double to char and try it again. Report your findings below:






  5. In Section 10 of vectorlab.cpp, proceed as in Section 9, but use the vector v4, which was constructed with a non-zero capacity. Answer the following:

    For a vector with initial capacity 0, the capacity increases when necessary by a fixed (machine-dependent) value.

    For a vector with initial non-zero capacity, the capacity doubles each time it increases.

F. Member Functions to access the first and last values

v.front(); Returns a reference to the first value stored in v
v.back(); Returns a reference to the back value stored in v

  1. Add a statement in Section 11 of vectorlab.cpp to output the first and last values of v5. Write your statement here:
    
        _____________________________________________________________ 
        
    Add statements to change the first element of v5 to 77 and the last element to 88 using these member functions. Write your statements here:
    
        _____________________________________________________________ 
    
        _____________________________________________________________ 
        
    Now, add a statement to output the contents of v5; give the output produced here:
    
        v5: _________________________________________________________ 
        

G. The Subscript Operator

Look at the definition of the function operator<<() at the beginning of vectorlab.cpp. Note the use of the subscript operator [] within a loop to output the contents of a vector. It is used in almost exactly the same way as for arrays. However, there is one important difference between vectors and C-style arrays.

  1. In Section 12 of vectorlab.cpp, try changing one of the elements in v5 using the subscript operator; i.e., use a statement of the form v5[#] = newvalue.
    Output the contents of v5 to see if it worked. Did it? ____________________
    Now do it again, but try appending a value with the subscript operator.
    Did it work? ____________________ If so, did the size of v5 change? ____________________
    Repeat it again, but try appending a value to v2 with the subscript operator.
    Did this work? ____________________ If so, did the size of v2 change? ____________________
    Now, try appending a value to the empty vector v6 with the subscript operator; that is, try assigning a value to v6[0]. Report what happens.






    The subscript operator should not be be used to append values to a vector, because neither its size nor its capacity is updated. Always use push_back() to append values to a vector because it updates its size (and, if ncessary, its capacity). Only after a vector contains values should the subscript operator be used to access (or change) those values.

    As with arrays, no range checking is performed on vectors to ensure that indices are in range.

    The attempt above to access v6[0] may have caused a fatal run-time error. If it did, comment out this statement before proceeding.

H. Assignment, Relational, and Swap Operators

v1 = v2 Assigns to v1 a copy of v2
v1 == v2 Returns true if and only if v1 has the same values as v2, in the same order
v1 < v2 Returns true if and only if v1 is lexicographically less than v2
v1.swap(v2) Swaps v1's contents with v2's

  1. In Section 13 of vectorlab.cpp, write statements to:
    1. Assign a copy of v2 to v3
    2. Then, check if they are equal using ==; output "true" if so, "false" otherwise. Output: ________________
    3. Check if v5 is less than v2, and output "true" if so, "false" otherwise. Output: ________________
    4. Swap the contents of v5 and v2 and then repeat (c): Output: ________________



Hand In:

  1. This lab handout with the answers filled in.
  2. A printout of a source listing of your completed program, vectorlab.cpp (use the enscript command from your Programming Style Sheet:
    enscript -E -G -2rj -M Letter -PECT2_PS vectorlab.cpp).
Category Points Possible Points Received
Lab Handout: (50) __________
Program vectorlab.cpp (50) __________

TOTAL

130

__________


Ricky J. Sethi <rickys at sethi.org>
Last modified: Mon Jun 9 16:25:13 PDT 2003