vector

advertisement
The vector template is defined in header file <vector>. Like all other standard library components, it resides in
namespace std.
The interface emulates the behavior of a C array (i.e., capable of fast random access) but with the additional
ability to automatically resize itself when inserting or removing an object.
The vector template can be instantiated with any type that fulfills the CopyConstructible and Assignable
requirements:[1]
expression return type
requirement
T&
t is equivalent to u
n/a
t is equivalent to T(t)
n/a
u is equivalent to T(u)
(const) T* denotes the address of u
n/a
n/a
t = u
T(t)
T(u)
&u
t.~T()
Where T is the type used to instantiate the vector, t is a value of T and u is a value of (possibly const) T.
For a given vector all elements must belong to the same type. For instance, one cannot store data in the form of
both char and int within the same vector instance. Vectors provide a standard set of functions for accessing
elements, adding elements to the end or anywhere, deleting elements and finding how many elements are
stored.
[edit] Individual element access
Individual elements of a vector can be accessed using the operation shown in the table below. Following the
standard convention for C and C++, the first element has index 0, and the last element has index size() - 1[2].
expression
v.at(i)
T&
or const
v[i]
T& or const
v.front() T& or const
v.back() T& or const
return type
bounds checking?
T& to the element at index i yes, throws out_of_range exception[2][3]
T& to the element at index i undefined behaviour if i >= v.size()
T& to the first element
undefined behaviour if v.empty() is true
T& to the last element
undefined behaviour if v.empty() is true
Where v is an object of type (possibly const) vector<T> and i represents the index.
[edit] Overview of functions
The vector class models the Container concept, which means it has begin(), end(), size(), max_size(),
empty(), and swap() methods.

informative
o
o
o
o
o

vector::front - Returns reference to first element of vector.
vector::back - Returns reference to last element of vector.
vector::size - Returns number of elements in the vector.
vector::empty - Returns true if vector has no elements.
vector::capacity - Returns current capacity (allocated memory)
standard operations
of vector.
o
vector::insert
- Inserts elements into a vector (single & range), shifts later elements up. O(n)
time.
o


vector::push_back
- Appends (inserts) an element to the end of a vector, allocating memory
for it if necessary. Amortized O(1) time.
o vector::erase - Deletes elements from a vector (single & range), shifts later elements down.
O(n) time.
o vector::pop_back - Erases the last element of the vector, O(1) time. Does not usually reduce
the memory overhead of the vector. Amortized O(1) time.
o vector::clear - Erases all of the elements. (This does not reduce capacity)
allocation/size modification
o vector::reserve - Changes capacity (allocates more memory) of the vector, if needed. In many
STL implementations capacity can only grow, and is never reduced. O(n) if the vector expands.
O(1) if not.
o vector::resize - Changes the vector size. O(n) time.
iteration
o vector::begin - Returns an iterator to start traversal of the vector.
o vector::end - Returns an iterator that points just beyond the end of the vector.
[edit] Vector iterators
In addition to the direct element access functions outlined above, the elements of a vector can be accessed
through vector iterators.
[edit] Capacity and reallocation
A typical vector implementation consists, internally, of a pointer to a dynamically allocated array,[2] and
possibly data members holding the capacity and size of the vector. The size of the vector refers to the actual
number of elements, while the capacity refers to the size of the internal array.
When new elements are inserted, if the new size of the vector becomes larger than its capacity, reallocation
occurs.[2][4] This typically causes the vector to allocate a new region of storage, move the previously held
elements to the new region of storage, and free the old region.
Because the addresses of the elements change during this process, any references or iterators to elements in the
vector become invalidated.[5] Using an invalidated reference causes undefined behaviour. Example:
#include <vector>
int main()
{
std::vector<int> v(1); // create a vector holding a single int with value 0.
int& first = *v.begin(); // make a reference to the first element
v.insert(v.end(), v.capacity(), 0); // append more elements to the vector, forcing a
reallocation
int i = first; // undefined behaviour; the reference has been invalidated
}
The reserve() operation may be used to prevent unnecessary reallocations. After a call to reserve(n), the vector's
capacity is guaranteed to be at least n.[6] Example:
#include <vector>
int main()
{
std::vector<int> v(1); // create a vector holding a single int with value 0.
v.reserve(10); // reserve space to prevent reallocation
int& first = *v.begin(); // make a reference to the first element
v.insert(v.end(), 5, 0); // append more elements to the vector
int i = first; // OK, no reallocation has occurred
}
The vector maintains a certain order of its elements, so that when a new element is inserted at the beginning or
in the middle of the vector, subsequent elements are moved backwards in terms of their assignment operator or
copy constructor. Consequently, references and iterators to elements behind the insertion point becomes
invalidated.[7] Example:
#include <vector>
int main()
{
std::vector<int> v(2); // constructs a vector holding two ints
// make references to the two ints
int& first = v.front();
int& last = v.back();
v.insert(v.begin() + 1, 1, 1); // insert a new int in the middle of the vector.
int i = first; // undefined behaviour if the previous insert caused reallocation
int j = last; // undefined behaviour per the C++ standard, §23.2.4.3/1
}
[edit] vector<bool> specialization
The Standard Library defines a specialization of the vector template for bool. The description of this
specialization indicates that the implementation should pack the elements so that every bool only uses one bit
of memory.[8] This is widely considered a mistake.[9][10] vector<bool> does not meet the requirements for a
C++ Standard Library container. For instance, a container<T>::reference must be a true lvalue of type T.
This is not the case with vector<bool>::reference, which is a proxy class convertible to bool.[11] Similarly,
the vector<bool>::iterator does not yield a bool& when dereferenced. There is a general consensus among
the C++ Standard Committee and the Library Working Group that vector<bool> should be deprecated and
subsequently removed from the standard library, while the functionality will be reintroduced under a different
name.[12] This change is unlikely to take place until after C++0x.
[edit] Usage
A C++ program that is to use vectors must #include <vector>. A vector is declared using:
std::vector<T> instance;
where "T" is the data type the vector is to store, and "instance" is the variable name of the vector. T can be any
Assignable type, including user-defined types.
An alternative to storing objects of type T is to store objects of type T*. This is useful if T is not Assignable, or
is expensive to copy.[13]
[edit] Replacement for arrays
In C++, arrays are contiguous pieces of memory. They are somewhat like blocks aligned together, each block is
then given a number, and to look at the contents of each block one only has to supply the number of the block.
All the elements of an array must be of the same type.
A vector is similar to a dynamically allocated array but with the ability to resize itself, and without the need for
manual deallocation of memory.
Because the elements of a vector are stored contiguously,[14] the address of the first element of a vector can be
passed to functions expecting an array (a pointer to the first element). The following example shows how a
vector can be used with the C Standard Library functions memcpy and printf:
#include <cstring> // memcpy
#include <vector>
#include <cstdio> // printf
int main()
{
using namespace std;
const char arr[] = "1234567890";
// construct a vector with 11 zero-initialized chars.
vector<char> vec(sizeof arr);
// copy 11 chars from arr into the vector
memcpy(&vec[0], arr, sizeof arr);
// prints "1234567890"
printf("%s", &vec[0]);
}
Note that such use of memcpy and printf is generally discouraged in favour of type safe alternatives from the
C++ Standard Library.[15]
[edit] Usage example
The following example demonstrates various techniques involving a vector and C++ Standard Library
algorithms, notably shuffling, sorting, finding the largest element, and erasing from a vector using the eraseremove idiom.
#include <iostream>
#include <vector>
#include <algorithm> // sort, max_element, random_shuffle, remove_if, lower_bound
#include <functional> // greater, bind2nd
// used here for convenience, use judiciously in real programs.
using namespace std;
int main()
{
int arr[4] = {1, 2, 3, 4};
// initialize a vector from an array
vector<int> numbers(arr, arr+4);
// insert more numbers into the vector
numbers.push_back(5);
numbers.push_back(6);
numbers.push_back(7);
numbers.push_back(8);
// the vector currently holds {1, 2, 3, 4, 5, 6, 7, 8}
// randomly shuffle the elements
random_shuffle( numbers.begin(), numbers.end() );
// locate the largest element, O(n)
vector<int>::const_iterator largest =
max_element( numbers.begin(), numbers.end() );
cout << "The largest number is " << *largest << "\n";
cout << "It is located at index " << largest - numbers.begin() << "\n";
// sort the elements
sort( numbers.begin(), numbers.end() );
// find the position of the number 5 in the vector, O(log n)
vector<int>::const_iterator five =
lower_bound( numbers.begin(), numbers.end(), 5 );
cout << "The number 5 is located at index " << five - numbers.begin() << "\n";
// erase all the elements greater than 4
numbers.erase( remove_if(numbers.begin(), numbers.end(),
bind2nd(greater<int>(), 4) ), numbers.end() );
// print all the remaining numbers
for(vector<int>::const_iterator it = numbers.begin(); it != numbers.end(); ++it)
{
cout << *it << " ";
}
return 0;
}
The output will be the following:
The largest number is 8
It is located at index 6 (implementation-dependent)
The number 5 is located at index 4
1234
Example of 2 dimensional dynamic vector array, and accessing and modifying it:
typedef std::vector< std::vector<int> > pxMP;
void function()
{
int sizeX, sizeY; // size can be set on-the-fly.
pxMP pxMap(sizeX, std::vector<int>(sizeY)); // X/Y array of pixels 0,1.
pxMap[0][5] = 1; /* accessing it */
// delete left and right columns:
pxMap.pop_back();
pxMap.erase(pxMap.begin());
// delete top and bottom rows of all columns, first make some tools:
std::vector< std::vector<int> >::iterator iterlvl2; // iterator level 2
dimension.
std::vector< int >::iterator iterlvl1; // iterator level 1 dimension
// lets' go deeper. We must go deeper.
for (iterlvl2=pxMap.begin();iterlvl2 != pxMap.end();iterlvl2++)
{
iterlvl1 = (*iterlvl2).begin(); // demo purpose only. so beautiful. access
granted, I N C E P T I O N.
(*iterlvl2).pop_back();
(*iterlvl2).erase((*iterlvl2).begin()); // where are we?
sizeY = (*iterlvl2).size(); // set new sizeY while on this level, once we
return to the higher level we cannot retrieve...
}
/* that was cool */
}
[edit] Vector visualization
Semantically picturing the vector push_back( data ) operation. Note the size of the vector increases from 6 to 7
after the operation.
Semantically picturing the vector pop_back() operation. Note the size of the vector decreases from 7 to 6 after
the operation.
Semantically picturing the vector resize( int ) operation. Note the size of the vector increases to 9, and the new
elements are filled with a default value.
[edit] Pros and cons








Like all dynamic array implementations, vectors have low memory usage and good locality of reference
and data cache utilization.
The vector data structure is able to quickly and easily allocate the necessary memory needed for specific
data storage. This is particularly useful for storing data in lists whose length may not be known prior to
setting up the list but where removal (other than, perhaps, at the end) is rare.
Like other STL containers, vectors may contain both primitive data types and complex, user-defined
classes or structs.
Unlike other STL containers, such as deques and lists, vectors allow the user to denote an initial capacity
for the container.
Vectors allow random access; that is, an element of a vector may be referenced in the same manner as
elements of arrays (by array indices). Linked-lists and sets, on the other hand, do not support random
access or pointer arithmetic.
Erasing elements from a vector or even clearing the vector entirely does not necessarily free any of the
memory associated with that element. This is because the maximum size of a vector since its creation is
a good estimate of the future size of the vector.
Vectors are inefficient at removing or inserting elements other than at the end. Such operations have
O(n) (see Big-O notation) complexity compared with O(1) for linked-lists. This is offset by the speed of
access - access to a random element in a vector is of complexity O(1) compared with O(n) for general
linked-lists and O(log n) for link-trees.
C++ vectors do not support in-place reallocation of memory, by design; i.e., upon reallocation of a
vector, the memory it held will always be copied to a new block of memory using its elements' copy
constructor, and then released. This is inefficient for cases where the vector holds plain old data and
additional contiguous space beyond the held block of memory is available for allocation.
Download