Back to blog
Backend Systemsbeginner

C++ STL: Containers, Algorithms & Iterators

Master the C++ Standard Template Library: vector, map, set, unordered_map, and 30+ algorithms. Learn to write expressive, efficient C++ with STL.

Asma HafeezApril 17, 20265 min read
cppstlcontainersalgorithmsiterators
Share:𝕏

C++ STL: Containers, Algorithms & Iterators

The STL gives you battle-tested, efficient data structures and algorithms. Using it well is what separates good C++ from great C++.


vector — Dynamic Array

CPP
#include <vector>
#include <algorithm>

std::vector<int> v = {3, 1, 4, 1, 5, 9};

// Access
v[0];            // 3 — no bounds check
v.at(0);         // 3 — throws std::out_of_range if invalid
v.front();       // 3
v.back();        // 9

// Modify
v.push_back(2);        // add to end
v.pop_back();          // remove from end
v.insert(v.begin(), 0); // insert at front (slow for large vectors)
v.erase(v.begin());     // remove first element

// Size
v.size();        // current count
v.capacity();    // allocated space (may be more than size)
v.reserve(100);  // pre-allocate — avoids reallocations
v.empty();       // true if size == 0
v.clear();       // remove all elements

// Iterate
for (int x : v) std::cout << x << " ";                    // range-for
for (auto it = v.begin(); it != v.end(); ++it) *it *= 2;  // iterator

// Sort
std::sort(v.begin(), v.end());                              // ascending
std::sort(v.begin(), v.end(), std::greater<int>());         // descending
std::sort(v.begin(), v.end(), [](int a, int b){ return a > b; }); // lambda

map and unordered_map

CPP
#include <map>
#include <unordered_map>

// map — ordered by key (binary tree), O(log n) operations
std::map<std::string, int> scores;
scores["Alice"] = 95;
scores["Bob"]   = 87;
scores["Carol"] = 92;

scores.at("Alice");        // 95 — throws if not found
scores.count("Dave");      // 0 — not found
scores.contains("Bob");    // true (C++20)

scores.erase("Carol");

for (const auto& [name, score] : scores) {  // structured binding
    std::cout << name << ": " << score << "\n";
}

// unordered_map — hash table, O(1) average, no ordering
std::unordered_map<std::string, int> fast_scores;
fast_scores["Alice"] = 95;

// Safe access with default
int s = fast_scores.count("Dave") ? fast_scores["Dave"] : 0;
// Or:
auto it = fast_scores.find("Dave");
if (it != fast_scores.end()) std::cout << it->second;

set and unordered_set

CPP
#include <set>
#include <unordered_set>

std::set<int> unique = {5, 3, 1, 4, 1, 5};  // {1, 3, 4, 5} — sorted, no dupes

unique.insert(2);          // {1, 2, 3, 4, 5}
unique.erase(3);           // {1, 2, 4, 5}
unique.count(4);           // 1 (exists)
unique.contains(10);       // false (C++20)

// Set intersection
std::set<int> a = {1, 2, 3, 4};
std::set<int> b = {2, 4, 6};
std::set<int> intersection;
std::set_intersection(a.begin(), a.end(), b.begin(), b.end(),
    std::inserter(intersection, intersection.begin()));
// intersection = {2, 4}

Other Containers

CPP
#include <list>
#include <deque>
#include <queue>
#include <stack>

// list — doubly linked list, O(1) insert/erase anywhere
std::list<int> lst = {1, 2, 3};
lst.push_front(0);
lst.push_back(4);

// deque — double-ended queue, O(1) push/pop at both ends
std::deque<int> dq = {1, 2, 3};
dq.push_front(0);
dq.push_back(4);

// queue — FIFO
std::queue<std::string> q;
q.push("first");
q.push("second");
std::string front = q.front();  // "first"
q.pop();

// stack — LIFO
std::stack<int> s;
s.push(1); s.push(2); s.push(3);
s.top();   // 3
s.pop();   // removes 3

STL Algorithms

All in #include <algorithm>.

CPP
#include <algorithm>
#include <numeric>
#include <vector>

std::vector<int> v = {3, 1, 4, 1, 5, 9, 2, 6};

// Search
auto it = std::find(v.begin(), v.end(), 4);       // iterator to 4
bool found = std::binary_search(v.begin(), v.end(), 4); // requires sorted!
int cnt = std::count(v.begin(), v.end(), 1);      // 2

// Sort
std::sort(v.begin(), v.end());
std::stable_sort(v.begin(), v.end());             // preserves equal order
std::nth_element(v.begin(), v.begin()+3, v.end()); // 4th element in place

// Transform
std::vector<int> doubled(v.size());
std::transform(v.begin(), v.end(), doubled.begin(),
    [](int x) { return x * 2; });

// Accumulate / reduce
int sum  = std::accumulate(v.begin(), v.end(), 0);
int prod = std::accumulate(v.begin(), v.end(), 1, std::multiplies<int>());

// Min/Max
auto minIt = std::min_element(v.begin(), v.end());
auto maxIt = std::max_element(v.begin(), v.end());
auto [mn, mx] = std::minmax_element(v.begin(), v.end());

// Copy / filter
std::vector<int> evens;
std::copy_if(v.begin(), v.end(), std::back_inserter(evens),
    [](int x) { return x % 2 == 0; });

// Remove-erase idiom (removes 1s from vector)
v.erase(std::remove(v.begin(), v.end(), 1), v.end());

// Reverse and rotate
std::reverse(v.begin(), v.end());
std::rotate(v.begin(), v.begin() + 2, v.end());  // rotate left by 2

// Check predicates
bool allPos = std::all_of(v.begin(), v.end(), [](int x){ return x > 0; });
bool anyBig = std::any_of(v.begin(), v.end(), [](int x){ return x > 100; });
bool noneNeg= std::none_of(v.begin(), v.end(),[](int x){ return x < 0; });

String Operations

CPP
#include <string>
#include <sstream>

std::string s = "Hello, World!";

s.length();               // 13
s.substr(0, 5);           // "Hello"
s.find("World");          // 7
s.replace(7, 5, "C++");   // "Hello, C++!"
s + " More";              // concatenation

// Split string by delimiter
std::vector<std::string> split(const std::string& s, char delim) {
    std::vector<std::string> result;
    std::stringstream ss(s);
    std::string token;
    while (std::getline(ss, token, delim)) {
        result.push_back(token);
    }
    return result;
}

auto parts = split("a,b,c,d", ',');
// {"a", "b", "c", "d"}

// Convert
int n = std::stoi("42");
double d = std::stod("3.14");
std::string str = std::to_string(42);

Ranges (C++20)

C++20 ranges make pipelines more readable.

CPP
#include <ranges>
#include <vector>

std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

// Filter even numbers, square them, take first 3
auto result = v
    | std::views::filter([](int x){ return x % 2 == 0; })
    | std::views::transform([](int x){ return x * x; })
    | std::views::take(3);

for (int x : result) std::cout << x << " ";  // 4 16 36

Key Takeaways

  1. Use vector by default — it's the fastest for sequential data
  2. unordered_map for fast lookup; map when you need sorted iteration
  3. Range-for (for (auto& x : container)) is cleaner than iterator loops
  4. STL algorithms are tested, optimized, and expressive — don't write your own loops when std::sort, std::find, or std::transform will do
  5. C++20 ranges make functional pipelines first-class — use them in new code

Enjoyed this article?

Explore the Backend Systems learning path for more.

Found this helpful?

Share:𝕏

Leave a comment

Have a question, correction, or just found this helpful? Leave a note below.