The C++ Standard Library

The C++ Standard Library: A Tutorial and Reference, 2nd Edition · Nicolai M. Josuttis ·1100 pages

Complete C++11 Standard Library reference — containers with complexity analysis, 50+ algorithms, iterator categories, move semantics, lambdas, smart pointers, and strings. The definitive STL guide.

Capabilities (9)
  • Select correct container from requirements (vector/deque/list/set/unordered_map)
  • Apply STL algorithms: sort, find_if, transform, remove/erase, accumulate, set_union
  • Use iterator categories and understand invalidation rules
  • Apply move semantics and perfect forwarding correctly
  • Write lambda expressions with correct capture modes
  • Choose between unique_ptr and shared_ptr ownership models
  • Use binary_search, lower_bound, upper_bound on sorted ranges
  • Apply numeric algorithms: accumulate, partial_sum, inner_product
  • Handle standard exception hierarchy and noexcept specification
How to use

Install this skill and Claude can select the right STL container for any access and insertion pattern, compose algorithms like sort, transform, remove_if, and accumulate into correct pipelines, and migrate raw-pointer ownership to unique_ptr and shared_ptr

Why it matters

Most C++ programmers know only a fraction of the Standard Library, leaving performance and correctness on the table — this skill closes that gap so Claude reaches for the right algorithm or container on the first try instead of suggesting a hand-written loop that reinvents a subtly buggy wheel

Example use cases
  • Deciding whether to use map or unordered_map for a cache with 10k entries by explaining the hash vs tree tradeoff and load-factor considerations
  • Removing all negative numbers from a vector in place using the erase-remove idiom with remove_if and explaining why erasing in a loop is incorrect
  • Rewriting a codebase's raw new/delete ownership model using make_unique and make_shared with correct weak_ptr observer links

C++ Standard Library Skill

Container Selection Guide

Need sequential access + fast random access?
  → vector (default choice for sequences)

Need fast insert/delete at both ends?
  → deque

Need fast insert/delete anywhere + stable iterators?
  → list (doubly linked) or forward_list (singly linked)

Need sorted unique keys with O(log n) lookup?
  → set / map

Need sorted non-unique keys?
  → multiset / multimap

Need O(1) average lookup, no ordering?
  → unordered_set / unordered_map

Need LIFO?
  → stack (adapter over deque/vector)

Need FIFO?
  → queue (adapter over deque)

Need priority queue (always extract min/max)?
  → priority_queue (adapter over vector with heap)

Container Complexity Summary

ContainerAccessInsert FrontInsert BackInsert MiddleFind
vectorO(1)O(n)O(1) amortO(n)O(n)
dequeO(1)O(1) amortO(1) amortO(n)O(n)
listO(n)O(1)O(1)O(1)O(n)
set/mapO(log n)O(log n)O(log n)
unorderedO(1) avgO(1) avgO(1) avg

Iterators

Iterator Categories

Input Iterator → forward only, read once
Output Iterator → forward only, write once
Forward Iterator → forward, multiple passes
Bidirectional Iterator → forward + backward (list, set, map)
Random Access Iterator → + arithmetic (vector, deque, array)

Key invariant: never use an iterator after the container is modified (invalidation rules vary by container).

Common Patterns

// Range-based for (C++11)
for (auto& elem : container) { ... }

// Algorithm with iterator range
std::sort(v.begin(), v.end());
std::find(v.begin(), v.end(), value);
std::copy(src.begin(), src.end(), std::back_inserter(dst));

// Reverse iteration
for (auto it = c.rbegin(); it != c.rend(); ++it) { ... }

STL Algorithms

Non-Modifying

std::find(first, last, value)            // linear search
std::find_if(first, last, pred)          // search with predicate
std::count(first, last, value)           // count occurrences
std::all_of/any_of/none_of(first, last, pred)
std::for_each(first, last, func)
std::equal(first1, last1, first2)
std::mismatch(first1, last1, first2)     // first differing pair

Modifying

std::copy(first, last, dest)
std::move(first, last, dest)
std::transform(first, last, dest, func)
std::replace(first, last, old, new)
std::fill(first, last, value)
std::generate(first, last, gen)
std::remove(first, last, value)          // doesn't resize! Returns new end.
// Always pair with erase: v.erase(std::remove(v.begin(), v.end(), val), v.end());

Sorting

std::sort(first, last)                   // unstable, O(n log n)
std::stable_sort(first, last)            // stable, O(n log² n)
std::partial_sort(first, middle, last)   // sort first k elements
std::nth_element(first, nth, last)       // k-th element + partition
std::is_sorted(first, last)

Searching (Sorted Ranges)

std::binary_search(first, last, value)  // bool
std::lower_bound(first, last, value)    // first >= value
std::upper_bound(first, last, value)    // first > value
std::equal_range(first, last, value)    // [lower, upper) pair

Set Operations (on sorted ranges)

std::set_union, set_intersection, set_difference
std::merge(first1, last1, first2, last2, dest)

Numeric

std::accumulate(first, last, init)          // sum
std::accumulate(first, last, init, op)      // with custom op (product, etc.)
std::inner_product(first1, last1, first2, init)
std::partial_sum(first, last, dest)
std::adjacent_difference(first, last, dest)

Move Semantics (C++11)

Core Concept

Move semantics allow transfer of resources instead of copying — O(1) for string/vector moves.

std::string s1 = "hello";
std::string s2 = std::move(s1); // s1 now empty, s2 owns the resource

Rules

  • std::move() casts to rvalue reference; doesn’t actually move
  • After move, source is in valid-but-unspecified state
  • Prefer move over copy when you no longer need the source
  • Containers automatically use move when elements are move-constructible

Perfect Forwarding

template<typename T>
void wrapper(T&& arg) {
    target(std::forward<T>(arg)); // preserves value category
}

Lambda Expressions (C++11)

// Capture modes
[=]         // capture all by value
[&]         // capture all by reference
[x, &y]     // x by value, y by reference
[this]      // capture this pointer

// Lambda as comparator
auto cmp = [](const auto& a, const auto& b) { return a.key < b.key; };
std::sort(v.begin(), v.end(), cmp);

// Lambda with mutable (modify captured-by-value)
int count = 0;
auto inc = [count]() mutable { return ++count; };

Smart Pointers

// Exclusive ownership
std::unique_ptr<T> p = std::make_unique<T>(args...);
// auto p = std::make_unique<T>(); // prefer make_unique

// Shared ownership
std::shared_ptr<T> p = std::make_shared<T>(args...);
std::shared_ptr<T> p2 = p; // reference count incremented

// Non-owning observer
std::weak_ptr<T> wp = sp;
if (auto locked = wp.lock()) { /* use locked */ }

Rule: use unique_ptr by default; use shared_ptr only when multiple owners needed; never use raw new/delete.


String Operations

std::string s = "hello world";
s.find("world")             // position or string::npos
s.substr(pos, len)          // substring
s.replace(pos, len, "new")  // replace portion
s.compare(other)            // 0 if equal
std::to_string(42)          // number to string
std::stoi("42")             // string to int
std::stod("3.14")           // string to double

// C++17 string_view (non-owning)
std::string_view sv = "hello"; // no copy

Exception Handling

// Standard exception hierarchy
std::exception
  std::logic_error → std::invalid_argument, std::out_of_range, std::domain_error
  std::runtime_error → std::overflow_error, std::underflow_error

// Throw by value, catch by reference
try { throw std::runtime_error("message"); }
catch (const std::exception& e) { std::cerr << e.what(); }

// noexcept specification
void f() noexcept;    // guarantees no exceptions

Functional Objects and Adaptors

// Standard function objects
std::less<T>, std::greater<T>, std::equal_to<T>
std::plus<T>, std::minus<T>, std::multiplies<T>
std::logical_and<T>, std::logical_not<T>

// Function wrappers
std::function<int(int, int)> f = [](int a, int b) { return a + b; };
auto bound = std::bind(func, _1, 42); // partially apply