C++ Standard Library · Lesson 5

Sets & Choosing a Container

The set — a collection of unique things with instant membership tests — and then the payoff: one flowchart to pick the right container for any access pattern.

🎯 The whole point: grab the right container, fast
The one idea

A set is a map with keys and no values — a collection of unique elements answering "is this in here?" fast. Once you know sets, you've met every container family — so this lesson ends with the selection rule: choose by access pattern, not by habit.

01 set & unordered_set — membership and dedup

When you only care whether something is present (not a value attached to it), use a set. Like maps, there's an ordered tree version and a hashed version — same trade-off as Lesson 4.

#include <unordered_set>

std::unordered_set<std::string> seen;

seen.insert("ada");
seen.insert("ada");            // no-op — sets hold UNIQUE elements
seen.size();                   // 1

if (seen.contains("ada")) { }    // C++20; O(1) average membership test
if (seen.count("bob")) { }       // 0 or 1 — works pre-C++20
seen.erase("ada");
Run on godbolt.org (-std=c++17+; contains needs C++20).

Dedup in two lines

Drop a range into a set and the duplicates vanish: std::unordered_set<int> u(v.begin(), v.end()); gives the unique values.

"Have I seen this?"

The canonical use: track visited nodes, processed IDs, seen tokens. if (!seen.insert(x).second) continue; — insert returns whether it was new.

ordered set bonus

std::set keeps elements sorted and supports range queries (lower_bound/upper_bound) — a sorted unique collection for free.

Source: cppreference — std::unordered_set · std::set.

02 The decision: pick by access pattern

You now know all the families. The skill the mission is after is choosing among them without thinking hard. Ask one question first — "how do I need to reach my data?" — and follow the tree:

How do you reach the data? Look up a value BY KEY? map sorted keys unordered_map just fast (default) Just MEMBERSHIP of unique items? set sorted unordered_set just fast (default) No — it's an ORDERED SEQUENCE Restricted access? stack queue priority_queue LIFO FIFO max first General access? array deque vector fixed N both ends DEFAULT When two fit, prefer the simpler / contiguous one. Start at vector. Move only when an access pattern above forces it. "No order needed" → pick the hashed (unordered_) version.
Three questions in order: lookup by key? → membership only? → otherwise a sequence. The leaf is your container.

Source: synthesized from cppreference — Containers & Core Guidelines SL.con.2. The same chart lives in the cheat sheet.

03 The selection table

What you needContainerWhy
A growable list, index accessvectorcontiguous, O(1) index, the default
Fixed size known at compile timearrayno heap, no growth, zero overhead
Fast push/pop at both endsdequeO(1) at front and back
Look up a value by keyunordered_map / mapO(1) avg / O(log n) sorted
Unique items, "is it in here?"unordered_set / setfast membership; set is sorted
Last-in-first-outstackLIFO discipline (Lesson 6)
First-in-first-outqueueFIFO discipline (Lesson 6)
Always pull the largest/smallest nextpriority_queuea heap (Lesson 6)
💡 The 90% rule In real code, vector and unordered_map cover the large majority of needs. Knowing precisely when to leave them — that's the expertise this chart encodes.

04 Gut-check: name the container

Phone book: name → number

unordered_map<string,string> — lookup by key, order irrelevant.

Leaderboard, top score first

priority_queue (or a sorted vector) — always want the max.

Unique visitor IDs today

unordered_set<long> — membership + automatic dedup.

Undo history

stack — last action undone first (LIFO).

RGB pixel rows to process in order

vector — sequence, index access, iterate fast.

Events sorted by timestamp, range queries

map<time,Event> — need sorted keys + ranges.

05 Check yourself

A set is best described as:
You need to remember which user IDs you've already processed. Best fit?
First question to ask when picking a container is:
You need a unique collection that you also iterate in sorted order. Pick:

06 Flashcards

Q: What is a set?
A: A collection of unique elements with fast membership testing — conceptually a map with keys and no values. set is sorted (tree); unordered_set is hashed.
Q: How do you dedup a vector's values?
A: Construct a set from its range: unordered_set<T> u(v.begin(), v.end()); — duplicates collapse automatically.
Q: What's the first question for choosing a container?
A: "How do I reach the data?" — by key (map), by membership (set), or as a sequence (vector/deque/array, or an adaptor). The access pattern picks the container.
Q: Two containers cover most real code — which?
A: vector (sequences) and unordered_map (key lookup). Leave them only when an access pattern demands it.
Q: How does insert tell you if an element was new?
A: It returns a pair<iterator,bool>; the .second bool is true if it was inserted, false if it was already present.
👩‍🏫 I'm your teacher — ask me anything

Best drill for this lesson: throw me a scenario — "I need to map URLs to hit counts and print the top 10" — and I'll walk the flowchart with you and name the container(s). Then we move from data structures to operating on them.