C++ STL Containers: vector, map, set, unordered_map & Adaptors Masterclass

โšก Modern C++ (C++17 / C++20 / C++23) ๐ŸŸข Lesson 14 ๐Ÿ“‚ Phase 14: STL Containers ๐Ÿ“… 2026 Master Edition
๐Ÿ“Œ Covered in this in-depth guide: vector & deque ยท list & forward_list ยท map & set ยท unordered_map & set ยท stack/queue/priority_queue ยท pair & tuple ยท optional & variant ยท Container Complexity

Welcome to Phase 14: STL Containers! The C++ Standard Template Library provides production-grade, generic, battle-tested data structures. Each container makes different trade-offs between time complexity, memory layout, and ordering guarantees. Choosing the right container is a key skill.

1Container Comparison Master Table
ContainerOrdered?AccessInsert/Erase (avg)Memory
std::vector<T>No (insertion)O(1) randomO(1) back / O(n) middleContiguous heap
std::deque<T>NoO(1) randomO(1) front & backChunked
std::list<T>NoO(n)O(1) any positionNode-based
std::set<T>SortedO(log n)O(log n)Red-Black tree
std::map<K,V>Sorted by keyO(log n)O(log n)Red-Black tree
std::unordered_set<T>NoO(1) avgO(1) avgHash table
std::unordered_map<K,V>NoO(1) avgO(1) avgHash table
std::stack<T>LIFOtop onlyO(1)Adaptor over deque
std::queue<T>FIFOfront onlyO(1)Adaptor over deque
std::priority_queue<T>Max heaptop = maxO(log n)Heap over vector
2Sequence Containers in Depth
C++ โ€” vector, deque, listโ–ถ Run in Compiler
#include <iostream>
#include <vector>
#include <deque>
#include <list>
#include <algorithm>

int main() {
    // โ”€โ”€โ”€ std::vector โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    std::vector<int> vec{10, 20, 30};
    vec.reserve(10);                  // pre-allocate capacity
    vec.push_back(40);
    vec.emplace_back(50);            // construct in-place
    vec.erase(vec.begin() + 1);      // remove element at index 1
    std::cout << "vector: ";
    for (int v : vec) std::cout << v << " ";
    std::cout << "| size=" << vec.size() << " cap=" << vec.capacity() << "
";

    // โ”€โ”€โ”€ std::deque โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    std::deque<int> dq{20, 30};
    dq.push_front(10);               // O(1) front insert
    dq.push_back(40);                // O(1) back insert
    std::cout << "deque: ";
    for (int d : dq) std::cout << d << " ";
    std::cout << "
";

    // โ”€โ”€โ”€ std::list (doubly-linked) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    std::list<int> lst{10, 30, 20, 40};
    lst.sort();                      // O(n log n) in-place
    lst.unique();                    // remove consecutive duplicates
    std::cout << "list sorted: ";
    for (int l : lst) std::cout << l << " ";
    std::cout << "
";
    return 0;
}
3Associative & Unordered Containers
C++ โ€” map, set, unordered_mapโ–ถ Run in Compiler
#include <iostream>
#include <map>
#include <set>
#include <unordered_map>
#include <string>

int main() {
    // โ”€โ”€โ”€ std::map (sorted by key, unique keys) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    std::map<std::string, int> scores;
    scores["Alice"] = 95;
    scores["Bob"]   = 87;
    scores.emplace("Charlie", 92);
    scores["Bob"] = 90;           // update

    std::cout << "Sorted scores:
";
    for (const auto& [name, score] : scores) {  // structured binding C++17
        std::cout << "  " << name << ": " << score << "
";
    }
    auto it = scores.find("Alice");
    if (it != scores.end()) std::cout << "Found Alice: " << it->second << "
";

    // โ”€โ”€โ”€ std::set (sorted, unique elements) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    std::set<int> primes{2, 3, 5, 7, 11};
    primes.insert(13);
    primes.insert(3);  // duplicate ignored
    std::cout << "Primes: ";
    for (int p : primes) std::cout << p << " ";
    std::cout << "
";

    // โ”€โ”€โ”€ std::unordered_map (O(1) average) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    std::unordered_map<std::string, int> wordCount;
    for (const std::string& word : {"the", "cat", "sat", "the", "cat", "the"})
        wordCount[word]++;
    std::cout << "Word counts:
";
    for (const auto& [w, c] : wordCount)
        std::cout << "  " << w << ": " << c << "
";
    return 0;
}
4Utility Types: pair, tuple, optional, variant
C++ โ€” pair, tuple, optional, variantโ–ถ Run in Compiler
#include <iostream>
#include <tuple>
#include <optional>
#include <variant>
#include <string>

// optional: a value that might not exist
std::optional<int> findIndex(const std::vector<int>& v, int target) {
    for (int i = 0; i < (int)v.size(); ++i)
        if (v[i] == target) return i;
    return std::nullopt;  // explicitly "no value"
}

int main() {
    // pair
    auto p = std::make_pair(42, std::string("hello"));
    std::cout << p.first << ", " << p.second << "
";

    // tuple
    auto t = std::make_tuple(1, 3.14, std::string("C++20"));
    std::cout << std::get<0>(t) << " " << std::get<1>(t) << " " << std::get<2>(t) << "
";

    // optional
    std::vector<int> nums{10, 20, 30, 40};
    if (auto idx = findIndex(nums, 30))
        std::cout << "Found at index: " << *idx << "
";
    else
        std::cout << "Not found
";

    // variant: type-safe union
    std::variant<int, double, std::string> v;
    v = 42;
    std::cout << "variant int: " << std::get<int>(v) << "
";
    v = std::string("hello variant");
    std::cout << "variant str: " << std::get<std::string>(v) << "
";
    return 0;
}
5Technical FAQs

Q1: When to use vector vs list?

Use vector by default โ€” cache-friendly contiguous memory wins in practice. Use list only when you need O(1) insert/erase at arbitrary positions with stable iterators.

Q2: What is emplace_back vs push_back?

emplace_back(args...) constructs the element in-place โ€” avoids a copy/move. push_back(obj) copies or moves an already-constructed object. Prefer emplace_back.

Q3: When does unordered_map degrade to O(n)?

In worst-case hash collisions, all keys land in the same bucket โ€” O(n) lookup. Prevent this with a good hash function or by using reserve() to avoid rehashing.

Q4: What is std::optional used for?

Return std::optional<T> from functions that may fail to produce a value โ€” instead of using sentinel values (-1, nullptr, or throwing exceptions for ordinary "not found" cases).

Q5: Difference between std::set and std::unordered_set?

std::set keeps elements sorted (O(log n) ops) using a Red-Black tree. std::unordered_set uses hashing for O(1) average ops but has no ordering guarantee.