The C++ standard library separates storage structures from algorithms through iterators and ranges. Container choice should follow required lookup, ordering, insertion, traversal, memory locality, and iterator-stability behavior rather than habit.
A vector is the default sequence for many workloads because contiguous storage supports fast traversal and random access. Ordered associative containers maintain sorted keys; unordered containers use hashing; adapters such as stack and queue expose restricted operations over another container.
The Standard Template Library provides containers, iterators, algorithms, function objects, and utilities. Start with std::vector for a dynamic sequence, std::map for ordered key-value lookup, std::unordered_map for average constant-time hashing, std::set for unique ordered values, and std::queue for first-in-first-out processing.
Use range-based loops for simple traversal and iterators when algorithms or positions are required. Algorithms such as sort, find_if, count_if, transform, and accumulate separate operation from storage. Include the correct headers and prefer algorithms over handwritten loops when they express the intent clearly.
Understand invalidation. Growing a vector may invalidate pointers, references, and iterators; erasing from containers has container-specific rules. Check whether lookup succeeded before dereferencing an iterator. Use const_iterator or const references when code should not modify elements.
Container choice affects memory layout and cache behavior as well as Big-O notation. vector offers contiguous storage and often outperforms node-based containers even when insertion complexity appears worse. Reserve capacity when size is predictable, but do not retain excessive memory without need.
Custom keys need ordering or hashing consistent with equality. Avoid modifying keys inside associative containers. Use emplace only when it actually constructs in place and improves clarity. Prefer transparent comparators for heterogeneous lookup where useful, and measure unordered container behavior under realistic hash distribution.
Modern C++ ranges and views compose filtering and transformation lazily. Be careful with view lifetime when the source is temporary or destroyed. Use execution policies only after confirming thread safety and benefit. Profile allocations, branch behavior, and data locality before replacing clear STL code with custom structures.
The examples pair operations with containers and make iterator, comparator, and complexity assumptions explicit.
Algorithms keep filtering, sorting, and aggregation explicit.
std::vector<int> scores{72, 91, 65, 88, 91};
std::sort(scores.begin(), scores.end(), std::greater<>{});
scores.erase(std::unique(scores.begin(), scores.end()), scores.end());
const int total = std::accumulate(scores.begin(), scores.end(), 0);
const auto passing = std::count_if(scores.begin(), scores.end(),
[](int score) { return score >= 70; });
Hash lookup provides a simple counting table.
std::unordered_map<std::string, std::size_t> frequency;
for (const std::string& word : words) {
++frequency[word];
}
std::vector<std::pair<std::string, std::size_t>> ranked(
frequency.begin(), frequency.end());
std::sort(ranked.begin(), ranked.end(),
[](const auto& a, const auto& b) {
return a.second > b.second;
});
A reallocation invalidates all iterators, pointers, and references. Erasing also invalidates positions at and after the erased element.
Use map for sorted keys and predictable logarithmic operations. Use unordered_map when hash lookup is suitable and ordering is irrelevant.
An algorithm states the intent clearly and has well-defined iterator and complexity requirements.
Explore 500+ free tutorials across 20+ languages and frameworks.