C++ course menu
C++ std::vector: Dynamic Arrays Explained with Examples
Learn std::vector, C++'s most used container: creating vectors, push_back and emplace_back, accessing with [] and at(), size and capacity, inserting and erasing, sorting, removing elements safely, vectors of strings and objects, and passing vectors to functions.
On this page
std::vector (from <vector>) is a resizable array. It stores elements next to each other in memory like an array, so it is fast, but it grows automatically as you add elements. It is the container you will use most in C++; when in doubt, use a vector.
Creating a vector#
#include <iostream>
#include <string>
#include <vector>
int main() {
std::vector<int> empty; // no elements
std::vector<int> scores = {72, 88, 95}; // three elements
std::vector<int> zeros(5); // five zeros
std::vector<std::string> names(3, "n/a"); // three copies of "n/a"
std::cout << empty.size() << ' ' << scores.size() << ' '
<< zeros.size() << ' ' << names[2] << '\n';
}0 3 5 n/aThe type in angle brackets is the element type: std::vector<double>, std::vector<std::string>, and so on.
Adding and removing at the end#
#include <iostream>
#include <vector>
int main() {
std::vector<int> stack;
stack.push_back(10);
stack.push_back(20);
stack.push_back(30);
std::cout << "Last: " << stack.back() << ", size: " << stack.size() << '\n';
stack.pop_back(); // removes the last element
std::cout << "Last: " << stack.back() << ", size: " << stack.size() << '\n';
}Last: 30, size: 3
Last: 20, size: 2Adding or removing at the end is fast. emplace_back(args...) builds the new element in place from constructor arguments, which is handy for objects.
Accessing elements#
Calling front(), back() or pop_back() on an empty vector is undefined behaviour, so check empty() first when the vector might be empty.
Looping#
#include <iostream>
#include <vector>
int main() {
std::vector<double> prices = {120.0, 45.5, 300.0};
for (double& p : prices) {
p *= 1.18; // add 18% tax in place
}
for (std::size_t i = 0; i < prices.size(); ++i) {
std::cout << i << ": " << prices[i] << '\n';
}
}0: 141.6
1: 53.69
2: 354Size and capacity#
A vector reserves some spare room so it does not need to reallocate on every push_back. size() is the number of elements; capacity() is how many fit before it must grow:
#include <iostream>
#include <vector>
int main() {
std::vector<int> v;
v.reserve(100); // allocate room for 100 elements up front
for (int i = 0; i < 10; ++i) v.push_back(i);
std::cout << v.size() << ' ' << v.capacity() << '\n';
}10 100When a vector grows past its capacity, it allocates a bigger block and moves every element. If you know roughly how many elements you will add, reserve avoids those repeated moves. Growth also means that references, pointers and iterators to elements become invalid after a push_back that reallocates.
Inserting and erasing in the middle#
insert and erase take an iterator (a position), usually written as v.begin() + index:
#include <iostream>
#include <vector>
void print(const std::vector<int>& v) {
for (int x : v) std::cout << x << ' ';
std::cout << '\n';
}
int main() {
std::vector<int> v = {10, 20, 30, 40};
v.insert(v.begin() + 1, 15); // insert before index 1
print(v);
v.erase(v.begin() + 3); // remove index 3
print(v);
v.clear(); // remove everything
std::cout << "Empty: " << std::boolalpha << v.empty() << '\n';
}10 15 20 30 40
10 15 20 40
Empty: trueInserting or erasing near the front moves every element after it, so it is slow for large vectors. You will learn more about iterators in Iterators.
Removing all matching elements#
To remove every element that matches a condition, C++20 provides std::erase and std::erase_if:
#include <iostream>
#include <vector>
int main() {
std::vector<int> nums = {5, -2, 8, -7, 3, 0, -1};
std::erase_if(nums, [](int n) { return n < 0; });
for (int n : nums) std::cout << n << ' ';
std::cout << '\n';
}5 8 3 0[](int n) { return n < 0; } is a lambda, a small unnamed function; see Lambdas. Before C++20, the same job needed the "erase-remove idiom" with std::remove_if.
Sorting and searching#
The algorithms in <algorithm> work on vectors:
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
int main() {
std::vector<std::string> names = {"Ravi", "Asha", "Meera", "John"};
std::sort(names.begin(), names.end());
for (const auto& n : names) std::cout << n << ' ';
std::cout << '\n';
auto it = std::find(names.begin(), names.end(), "Meera");
if (it != names.end()) {
std::cout << "Meera is at index " << (it - names.begin()) << '\n';
}
}Asha John Meera Ravi
Meera is at index 2Algorithms covers many more.
Passing vectors to functions#
Pass by const reference to read, by reference to modify, and return by value to produce a new vector:
#include <iostream>
#include <vector>
std::vector<int> evens(const std::vector<int>& values) {
std::vector<int> result;
for (int v : values) {
if (v % 2 == 0) result.push_back(v);
}
return result;
}
int main() {
for (int e : evens({3, 8, 12, 5, 6})) std::cout << e << ' ';
std::cout << '\n';
}8 12 6Returning a vector by value is cheap in modern C++, because it is moved (or built directly in place), not copied.
Common mistakes#
Practice#
Practice exercise
Read numbers from std::vector<int> data = {4, 9, 4, 1, 9, 9, 7}; into a new vector that keeps only the first occurrence of each value, in the original order. Print it.
Show solution
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> data = {4, 9, 4, 1, 9, 9, 7};
std::vector<int> unique;
for (int x : data) {
if (std::find(unique.begin(), unique.end(), x) == unique.end()) {
unique.push_back(x);
}
}
for (int x : unique) std::cout << x << ' ';
std::cout << '\n';
}4 9 1 7For large inputs, track seen values in a std::unordered_set instead, which makes each check fast; see unordered_map and unordered_set.
Practice exercise
Write std::vector<int> running_total(const std::vector<int>& v) that returns the running totals, so {3, 1, 4, 1, 5} gives {3, 4, 8, 9, 14}.
Show solution
#include <iostream>
#include <vector>
std::vector<int> running_total(const std::vector<int>& v) {
std::vector<int> result;
result.reserve(v.size());
int sum = 0;
for (int x : v) {
sum += x;
result.push_back(sum);
}
return result;
}
int main() {
for (int x : running_total({3, 1, 4, 1, 5})) std::cout << x << ' ';
std::cout << '\n';
}3 4 8 9 14Key takeaway#
Finished this lesson?