C++ Vectors
Arrays -- good and (mostly) bad
An array is used to contain a set of data all which are the same
type such as names, ages, or grades.
The good
- Arrays can be indexed for easy reference to individual elements.
- Dicussion Point -- what else is good about an array?
The bad
- The size of the array must be declared at compile time and cannot be changed
(without using dynamic memory allocation).
- We must use a separate variable to keep track of the number of elements
in the array that are actually used.
- If we use an array index that's out-of-bounds, our program crashes.
- The name of an array is like a pointer which can be
very confusing (e.g. when passed to a function).
- Elements of an array are not automatically initialized.
- We can't assign one array to another unless we write code to do so.
- Discussion Point -- what else is bad about an array?
The C++ vector is similar to an array, but also has differences
which overcome the "bad".
Generally we prefer to use vectors instead of arrays,
although there are some programming situations in which an array is required.
(E.g. argv, functions from the C-string library such as toupper()).
To use a vector, you must include its associated header file
-- #include <vector>.
The vector is one of many container provided by the C++ Standard Template
Library (STL). The containers provide an interface which
allows you to use the container without being concerned with the details.
Vectors are similar to Arrays
The statement vector< int > integers(10);
creates a vector which contains 10 integers and initializes them to zero.
It's analgous to int integers[10];
Similarly, the statement vector< string > names(12); creates
a vector containing 12 strings all initialized to the empty string.
We can also provide an explicit initial value for each
element of the vector.
The statement vector< int> integers (10, -1);
creates the same vector as above, but all elements are intialized to -1.
And the statement vector< string > names( 12, "bob");
creates the vector of 12 strings, but initalizes them all to "bob".
A vector can be created as a copy of an existing vector.
The code
vector< string > names (12, "bob");
vector< string > moreNames ( names );
creates the vector moreNames as a copy of the vector names
We can access each member of the vector.
We can use brackets ( [ ] ) just like an array.
vector< int > integers(10);
integers[3] = 7;
for (int i = 0; i < 10; i++)
cout << integers[i];
//-----------------------------
vector < string > myStrings(5);
string mary ("mary");
myStrings[0] = "bob";
myStrings[4] = mary;
//-----------------------------
vector < Bicycle > bikes(50);
Bicycle myBike;
bikes[2] = bikes[6] = myBike;
However, this method has the same risks as with arrays -- no checking is
done to see that the index is valid. If the index is invalid, anything
might happen.
An alternative is to use the vector's at( ) operation. This operation
does the same thing as using brackets,
so the statements integers[4] = 12;
and integers.at( 4 ) = 12; do the same thing, but the at( )
operation checks the index. If the index is out-of-bounds, at( ) "throws
an exception" which at present will cause our program to abort immediately, but which we can
deal with later.
The code above is better written as
vector< int > integers(10);
integers.at( 3 ) = 7;
// brackets ok in controlled loop
for (int i = 0; i < 10; i++)
cout << integers[ i ];
//-----------------------------
vector < string > myStrings(5);
string mary ("mary");
myStrings.at( 0 ) = "bob";
myStrings.at( 4 ) = mary;
//-----------------------------
vector < Bicycle > bikes(50);
Bicycle myBike;
bikes.at( 2 ) = bikes.at( 6 ) = myBike;
Vectors are different from Arrays
We can create an empty vector, but not an empty array
// an empty vector that will hold ints
vector< int > integers;
A vector will grow automatically larger as needed when new
elements are inserted at the "end" of the vector using the vector's
push_back( ) operation. Arrays are fixed size.
integers.push_back (5);
integers.push_back (4);
integers.push_back (3);
This initially empty vector now contains 3 elements. As more elements
are added using push_back( ), the vector will continue
to get larger.
The vector has an operation that lets us ask how many elements are in
currently stored in the vector.
int nrElements = integers.size( );
for (unsigned int i = 0; i < integers.size( ); i++)
cout << integers.at( i ) << endl;
Note that the size( ) operation returns an unsigned int, and
hence the for-loop index must be also be declared as an unsigned int.
The vector has an operation that lets us ask how many elements the
vector can hold -- aka the vector's "capacity". Don't confuse capacity with size.
Note that the vector's
capacity will automatically grow as the result of adding elements using push_back.
cout << integers.capacity( ) << endl;
We can assign one vector to another, just like primitive variable types.
Array assignment is not supported in this way. To assign arrays you
would need to write a function.
vector< int > copyOfIntegers;
copyOfIntegers = integers;
We can remove a single element of a vector and the vector will
automatically shrink and compress the data together
// remove integers[i]
// make the vector smaller and fill-in the hole
integers.erase( integers.begin() + i);
In this code, integers.begin( ) is an iterator that is used
to "point to" the first element of the vector. We'll discuss iterators later
in the course.
The capacity of the vector may also be explictly changed using
the operations reserve( ) and resize( ).
// make the capcity at least 32 elements
integers.reserve( 32 );
// set the capcity to 10 more than the current number of elements
integers.reserve( integers.size( ) + 10);
// change the size to 24 elements
integers.resize( 24 );
Vectors also support other useful operations
empty( ) -- returns true if the vector is empty
clear ( ) -- removes all elements from the vector
Multiple Dimensions
We can define an array to have (almost) as many dimensions as we need.
The elements of the array are then accessed with multiple indices.
int scores[ 4 ][ 10 ];
int cube[3][3][3];
scores[3][2] = 99;
cube[1][2][0] = -1;
With vectors, the approach is a little different. We declare an
empty "vector of vector of int".
// vector of vector of int
vector< vector > scores;
// vector of vector of vector of int
vector< vector< vector > > cube;
Unlike the array declaration above, the vector declaration does not
allocate any memory (the vectors are all empty). Your program must
dynamically allocate the memory for each vector. We'll show you
how to do that a bit later.
Once the vectors have been allocated, we use multiple indicies to
access the elements, just like with arrays.
Last Modified: Monday, 28-Aug-2006 10:16:07 EDT