Vectors in C++ are one of the most powerful sequence containers, offering dynamic resizing and memory management capabilities. In this comprehensive guide, we’ll explore everything from vector initialization to advanced vector manipulation, making it an essential resource for C++ developers aiming to master this versatile container.
What is a Vector in C++?
A vector in C++ is a dynamic array that automatically resizes itself when elements are added or removed. Unlike arrays with fixed sizes, the C++ vector container can expand or shrink at runtime, making it highly versatile for handling dynamic data. The underlying storage of vectors is managed by the container itself.
Just like arrays, vector elements are stored in adjacent memory locations, allowing for efficient access using iterators or the subscript operator ([]
). You can also access elements by passing a pointer to any C++ function expecting a pointer to an array element.
One key feature of vectors is that data is inserted at the end, which may trigger reallocation to extend the storage. This efficient memory management is what allows vectors to grow and shrink dynamically. While this flexibility comes at the cost of some extra memory usage, C++ vectors are more efficient in accessing elements than other sequence containers, such as deques
and lists
.
The rest of the article is organized as following:
Table of Contents
How to Declare a Vector in C++
Initializing a Vector in C++
C++ Vector Functions
Traversing C++ Vectors using Iterators
Accessing C++ Vector Elements by using Access Functions
Manipulate Vector Elements by using Modifier Functions
C++ Vector Capacity and Size Functions
When is the vector most efficient in C++?
Zero Sized Vectors
We also developed the following C++ Vector example programs to demonstrate different functions of a vector in C++.
C++ Program to Access Vector Elements
C++ Program to Manipulate Vector Elements
C++ Program to display number of elements in a Vector
How to Declare a Vector in C++
To declare a vector, include the <vector>
header file. Below is the syntax:
1 2 | template < class T, class Allocator = std::allocator<T> > class vector; |
Vector Parameters
- T represents the type of elements, which can be any data type (including user-defined types).
- Allocator − Type of allocator object. By default, the allocator class template is used, which defines the memory allocation/de-allocation model.
Initializing a Vector in C++
A vector in C++ can be initialized in multiple ways. For example, initialize the vector as a list.
Method 1:
1 | vector<int> my_vector = {1, 2, 3, 4}; |
Another way is to initialize the vector by assigning the value directly to the vector.
1 | vector<int> my_vector {1, 2, 3, 4}; |
Method 2:
Another way to initialize the vector to a predefined size with a single value. vector<int> my_vector (3, 4);
Here the vector is defined with the size of 3 elements and all having the value 4, which is equivalent to the following.
1 | vector<int> my_vector = {4, 4, 4}; |
C++ Vector Functions
Vector library provides lots of functions to traverse, access and manipulate vectors. There are a lot many helper/utility vector functions to determine the capacity and size of vectors.
Traversing C++ Vectors using Iterators
As vector elements are placed in contiguous storage so that they can be accessed and traversed using iterators. There are four basic functions associated with vectors which are used to traverse vectors i.e.
- begin() – Returns an iterator pointing to the first element in the vector
- end() – Returns an iterator pointing to the theoretical element that follows last element in the vector
- rbegin() – Returns a reverse iterator pointing to the last element in the vector (reverse beginning). It moves from last to first element
- rend() – Returns a reverse iterator pointing to the theoretical element preceding the first element in the vector (considered as reverse end)
C++ Program to demonstrate Vector Iterators
Consider the following program which demonstrate the use of iterators to access and traverse vector elements using the iterator member types discussed above.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | #include <iostream> #include <vector> using namespace std; int main() { vector <int> scores; vector <int> :: iterator i; vector <int> :: reverse_iterator ri; for (int i = 1; i <= 5; i++){ scores.push_back(i); } cout << "Output of begin() and end():"; for (i = scores.begin(); i != scores.end(); ++i){ cout << ' ' << *i; } cout << endl << endl; cout << "Output of rbegin() and rend():"; for (ri = scores.rbegin(); ri != scores.rend(); ++ri){ cout << ' ' << *ri; } return 0; } |
This C++ program demonstrates how to use both forward and reverse iterators to access and traverse the elements of a vector. It first populates the vector scores
with integers from 1 to 5 using the push_back()
function.
Output:
1 2 3 | Output of begin() and end(): 1 2 3 4 5 Output of rbegin() and rend(): 5 4 3 2 1 |
Accessing C++ Vector Elements by using Access Functions
Vector elements can be accessed using the following vector functions. Any/combination or all of these functions can be used to access vector elements in different situations.
- front() – Returns a reference to the first element in the container.
- back() – Returns reference to the last element in the container.
- at() – Returns a reference to the element at specific position in the vector by using a reference operator (as mentioned below)
- Reference Operator [r] – Returns a reference to the element at position ‘r’ in the vector
C++ Program to Access Vector Elements
Consider the following program which demonstrate the access and traverse vector elements using the access functions as discussed above.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | #include <iostream> #include <vector> using namespace std; int main() { vector <int> ints = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; cout << "Using at() function - Value returned by ints.at(4) = " << ints.at(4); cout << endl; cout << "Using front() function - Value returned by ints.front() = " << ints.front(); cout << endl; cout << "Using back() function - Value returned by ints.back() = " << ints.back(); cout << endl; cout << "Reference Operator [r] : Value at position ints[2] = " << ints[2]; cout << endl; return 0; } |
This C++ program demonstrates how to access and traverse elements in a vector using various access functions. It initializes a vector ints
with values from 1 to 10 and then uses four different access methods to retrieve specific elements:
at()
: Safely accesses an element at a specific index, in this case, the element at index 4.front()
: Returns the first element of the vector.back()
: Retrieves the last element of the vector.- Subscript operator
[]
: Directly accesses the element at a specific index, here at index 2.
Each method prints the corresponding element which shows the different ways to retrieve vector elements in C++.
Output:
1 2 3 4 5 6 7 | Using at() function - Value returned by ints.at(4) = 5 Using front() function - Value returned by ints.front() = 1 Using back() function - Value returned by ints.back() = 10 Reference Operator [r] : Value at position ints[2] = 3 |
Manipulate Vector Elements by using Modifier Functions
The following C++ Vector functions are used to interact with vector elements and manipulate them.
insert()
: Inserts elements at a specified position in the vector.assign()
: Replaces the vector’s content with new values and resizes it.emplace()
: Constructs and inserts an element directly at a given position.push_back()
: Adds an element to the end of the vector, increasing its size.emplace_back()
: Constructs and adds an element to the end of the vector.pop_back()
: Removes the last element, reducing the size of the vector.resize()
: Adjusts the size of the vector by adding or removing elements.swap()
: Exchanges the contents of two vectors.clear()
: Deletes all elements from the vector, leaving it empty.erase()
: Removes specific elements or a range of elements from the vector.
C++ Program to Manipulate Vector Elements
Consider the following program which demonstrate the manipulation of vector elements using the modified functions as discussed above.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | #include <iostream> #include <vector> using namespace std; void print_vec(const vector<int>& vec) { for (auto x: vec) { cout << ' ' << x; } cout << '\n'; } int main () { cout << "Initial Vector:" << endl; vector<int> vec(3,100); print_vec(vec); cout << "Insert Value: 200 at the beginning of Vector:" << endl; auto it = vec.begin(); it = vec.insert(it, 200); print_vec(vec); cout << "Insert Value: 300 twice at the end of Vector:" << endl; it = vec.end(); vec.insert(it,2,300); print_vec(vec); } |
This C++ program demonstrates how to manipulate vector elements using various modifier functions.
Output:
1 2 3 4 5 6 7 8 9 10 11 | Initial Vector: 100 100 100 Insert Value: 200 at the beginning of Vector: 200 100 100 100 Insert Value: 300 twice at the end of Vector: 200 100 100 100 300 300 |
C++ Vector Capacity and Size Functions
The following C++ Vector functions are used to manipulate vector size and capacity.
- empty() – This function checks whether the container is empty or not.
- size() – Returns the number of elements in the vector
- max_size() – Returns the maximum possible number of elements of vector
- reserve() – Reserves storage i.e. increase the capacity of the vector to a value that’s greater or equal to new_cap by pre-allocatong the memory.
- capacity() – Returns the number of elements that can be held in currently allocated storage
- shrink_to_fit() – Reduces memory usage by freeing unused memory
C++ Program to display number of elements in a Vector
The following C++ program displays the number of elements in vector using size() function.
1 2 3 4 5 6 7 8 9 10 11 | #include <vector> #include <iostream> using namespace std; int main() { vector<int> ids {1, 3, 5, 7}; cout << "ids contains " << ids.size() << " elements.\n"; } |
Output:
1 | ids contains 4 elements. |
When is the Vector most efficient in C++?
Vector is more efficient when you reserve() the correct amount of storage at the beginning so the vector never has to reallocate.
Vector is more efficient when you only add and remove elements from the back end.
It is possible to insert and erase elements from the middle of a vector using an iterator, however, when an object is inserted into the vector in the middle, it must push other objects down to maintain the linear array.
Zero Sized Vectors
A zero-sized vector is a vector that has been initialized but contains no elements. This is a valid state for a vector in C++. Zero sized vectors are also possible and valid. In that case vector.begin() and vector.end() points to same location. But behavior of calling front() or back() is undefined.
- Empty Vector: A zero-sized vector is essentially an empty vector, meaning its size is
0
, but it still has the capacity to grow and add elements later. The vector is valid, and it can still be used with certain operations, like adding or inserting elements. - Iterators in Zero-Sized Vectors:
- In a zero-sized vector, the
begin()
andend()
iterators point to the same memory location, which represents the position after the last element (or the first, since there are no elements). This is because there is no valid element in the vector to traverse, so both iterators point to a common “null” position. - You can safely check for an empty vector using the condition
if (vector.begin() == vector.end())
, which will return true if the vector is empty.
- In a zero-sized vector, the
- Undefined Behavior with
front()
andback()
:- Calling
front()
orback()
on a zero-sized vector results in undefined behavior because these functions assume that the vector contains at least one element. Since there is no first or last element in a zero-sized vector, attempting to access them can lead to crashes or unpredictable results. - To avoid this, always check if the vector is empty (
vector.empty()
) before usingfront()
orback()
to ensure the vector has elements.
- Calling
While zero-sized vectors are valid and commonly used in dynamic memory scenarios, care must be taken when accessing elements, as functions like front()
and back()
do not work on empty vectors and can lead to undefined behavior.
Summary
This article thoroughly explains vectors in C++, a dynamic array-like container that automatically resizes during runtime. It covers essential topics such as how to declare, initialize, and traverse vectors using iterators. The article delves into key vector functions like insert()
, push_back()
, resize()
, and swap()
, showing how to manipulate vector elements. Additionally, it explains vector capacity and size functions such as size()
, capacity()
, and reserve()
, emphasizing efficient memory management. Several C++ code examples are provided to demonstrate practical uses of vectors in real-world programming scenarios. Special attention is given to the behavior of zero-sized vectors and how to avoid common pitfalls, like using front()
or back()
on an empty vector. This comprehensive guide is ideal for developers looking to master vectors in C++ programming.
Frequently Asked Questions about Vectors in C++
1. What is the difference between a vector and an array in C++?
- Answer: The key difference is that vectors are dynamic in size, meaning they can grow or shrink during runtime, whereas arrays have a fixed size determined at compile-time. Vectors also handle memory management internally, making them easier to use when the size of the data set changes frequently. Arrays, on the other hand, are more efficient in terms of memory usage for fixed-size data.
2. How does vector memory allocation work in C++?
- Answer: Vectors in C++ allocate extra memory to accommodate future growth. When a vector exceeds its current capacity, it automatically allocates a larger block of memory (usually doubling the size), copies the existing elements into the new space, and frees the old memory. This helps minimize the overhead of frequent memory allocations as the vector grows.
3. Can vectors store objects of different data types?
- Answer: No, vectors are type-safe containers, which means they can only store elements of the same data type. However, you can create a vector of objects where each object is a different type, as long as they inherit from a common base class or use smart pointers like
std::variant
orstd::any
for mixed-type storage.
4. What is the most efficient way to add elements to a vector in C++?
- Answer: The most efficient way to add elements to a vector is by using
push_back()
oremplace_back()
to append elements to the end of the vector. For better performance, if you know the number of elements in advance, usereserve()
to allocate sufficient memory upfront and avoid repeated reallocations.
5. How can I remove elements from a C++ vector efficiently?
- Answer: Removing elements from the back of the vector using
pop_back()
is efficient since it doesn’t involve shifting elements. However, removing elements from the middle or front requires shifting all subsequent elements, which can be slower. If you need to frequently erase elements from the middle, consider using other containers likestd::list
for better performance.