Vector Overview
C-style arrays in C and C++ are not dynamic - the compiler needs to know the size of the array (the type and number of elements) in order to properly allocate memory. This is quite different to interpreted languages like Python, PHP and JavaScript, where arrays are inherently dynamic - you don’t need to specify data type and size in advance.
Vectors in C++ are standard containers which provide powerful dynamic-array like functionality, with fixed-time access to elements in any order. Vectors are defined by a template class available in the standard library - you just need to add #include <vector>
to your header file to have access to vector functionality.
A C++ vector can be described as a dynamic C-style array - with fast and efficient access to individual elements in any order. You don’t need to worry about memory and size allocation. Subscripting (i.e. myVector[]
) access is provided as with C-style arrays.
Vectors work by setting up an initial memory allocation for your data. If more data is added and the allocation is exceeded, the vector class creates a new, bigger array in memory. The old array is copied across to the new, before being deleted. This is all abstracted away so you don’t need to worry about it, though you should probably take measures to minimise re-allocation - which will help maximise performance.
This article is an ongoing summary of my notes on functions in C++. Please don’t assume that what you read here is accurate. For a more complete description of vectors in C++, check the references presented below.
DECLARATION
Include the appropiate header to give access to the vector class. Then declare the vector - which shoudl specify the data type that will be contained by the vector:
For convenience, you can use a typedef
statement to make declarations more concise:
INITIALIZING
To initialize, you can use an initializer list provided your compiler supports this. This method works with g++ version 5.4.0 on Ubnuntu, compiling with the c++11
flag.
You can also specify the initial size during the declaration, and only set values later:
The reserve() method is a better option for specifying an original size rather than using the vector constructor, which will cause problems when the vector holds aggregate data:
ADDING ELEMENTS
The vector.assign(n, el)
method overwrites the vector, such that it contains n
elements, each defined by el
.
The vector.push_back(el)
method appends an element to the vector.
To add an element to a position specified by an iterator use vector.insert()
.
Examples:
Note that:
assign()
overwrites the vectorinsert()
requires an iterator as first parameter, not a simple indexpush_back()
appends to the vector
ADD ELEMENTS AT A PRECISE POSITION
Note that if a reallocation is triggered by emplace()
(i.e. the allocated memory block grows), all iterators, pointers and references for the container are invalidated. If no reallocation occurs, only those pointing to the position and beyond are invalidated. All iterators, pointers and references to elements before position keep referring to the same elements they were referring to before the emplace()
call.
MORE EFFICIENT APPENDING
The vector::emplace_back()
function inserts a new element at the end of the vector.
The new element is constructed in place using the provided arguments. This avoids a copy action, improving efficiency as compared with push_back()
.
The allocated storage space will only be extended if the new vector size exceeds the current vector capacity.
When the vector element is made up of aggregate data (like a struct), the benefits of emplace_back()
vs push_back()
may be negated. In this case, you should use an initialiser list constructor in the data structure, which will allow the new element to be constructed in-place without a copy.
CLEAR
The clear()
method removes all elements:
ERASE
Deletes a single element from a vector.
OPTIMIZATION
When the memory allocated for your vector is exceeded as the vector grows, a re-allocation is triggered. Re-allocation is resource-expensive and should be avoided if possible.
One simple way of avoiding unnecessary reallocation is to set a rational capacity for the vector with vector.reserve(). If you do this, re-allocation won’t occur until you exceed the defined reserve.
The method vector.reserve(n)
sets the vector capacity such that n elements can be contained. If n
is greater than the current vector capacity the container storage will be reallocated, increasing its capacity to n
(or greater). vector.reserve()
has no effect on vector size and does not alter the vector elements.
If n
is less than the current capacity the function call does not cause a reallocation and the vector capacity is not affected.
Last updated