C++ course menu
C++ std::map: Key-Value Pairs, Lookup, Insert, Erase and Iteration
Learn std::map in C++: creating maps, inserting and updating with [], insert and insert_or_assign, safe lookups with find, contains and at, erasing, iterating in sorted key order with structured bindings, custom ordering, and multimap.
On this page
A std::map (from <map>) stores key-value pairs, where each key is unique and maps to one value: a word and its meaning, a student and their marks, a product code and its price. A map keeps its keys sorted, and finds, inserts and removes keys in O(log n) time.
Creating a map and adding entries#
#include <iostream>
#include <map>
#include <string>
int main() {
std::map<std::string, int> ages = {
{"Ravi", 25},
{"Asha", 21},
};
ages["Meera"] = 23; // add a new key
ages["Ravi"] = 26; // update an existing key
for (const auto& [name, age] : ages) {
std::cout << name << ": " << age << '\n';
}
std::cout << ages.size() << " people\n";
}Asha: 21
Meera: 23
Ravi: 26
3 peopleThe keys print in alphabetical order, no matter the order of insertion. Each element is a std::pair<const Key, Value>; the structured binding [name, age] unpacks it.
The [] trap: it inserts#
map[key] returns the value for key, creating it with a default value if it does not exist. That is perfect for counting, but a silent bug when you only meant to look:
#include <iostream>
#include <map>
#include <string>
int main() {
std::map<std::string, int> stock = {{"pens", 40}};
std::cout << stock["books"] << '\n'; // inserts "books" with 0!
std::cout << stock.size() << '\n';
}0
2[] also cannot be used on a const map. For lookups, use the methods below.
Looking up safely#
#include <iostream>
#include <map>
#include <stdexcept>
#include <string>
int main() {
std::map<std::string, double> prices = {{"tea", 20}, {"coffee", 35}};
if (auto it = prices.find("coffee"); it != prices.end()) {
std::cout << it->first << " costs " << it->second << '\n';
}
std::cout << std::boolalpha << prices.contains("juice") << '\n'; // C++20
try {
std::cout << prices.at("juice") << '\n';
} catch (const std::out_of_range&) {
std::cout << "juice is not on the menu\n";
}
}coffee costs 35
false
juice is not on the menuUse find when you need the value afterwards, so the key is only searched once.
Inserting without overwriting#
insert adds a key only if it is not already present, and tells you whether it did:
#include <iostream>
#include <map>
#include <string>
int main() {
std::map<std::string, std::string> users = {{"asha", "asha@example.com"}};
auto [it1, added1] = users.insert({"ravi", "ravi@example.com"});
auto [it2, added2] = users.insert({"asha", "new@example.com"});
std::cout << std::boolalpha << added1 << ' ' << added2 << '\n';
std::cout << users["asha"] << '\n';
users.insert_or_assign("asha", "asha.rao@example.com"); // C++17: always sets
std::cout << users["asha"] << '\n';
}true false
asha@example.com
asha.rao@example.comErasing#
#include <iostream>
#include <map>
int main() {
std::map<int, char> grades = {{1, 'A'}, {2, 'B'}, {3, 'C'}, {4, 'D'}};
grades.erase(2); // by key
std::erase_if(grades, [](const auto& entry) { return entry.second == 'D'; }); // C++20
for (const auto& [roll, grade] : grades) std::cout << roll << grade << ' ';
std::cout << '\n';
}1A 3CCounting and grouping#
Two very common patterns: counting occurrences, and grouping items under a key:
#include <iostream>
#include <map>
#include <string>
#include <vector>
int main() {
std::vector<std::string> words = {"apple", "avocado", "banana", "blueberry", "cherry", "apricot"};
std::map<char, std::vector<std::string>> by_letter;
for (const auto& w : words) {
by_letter[w[0]].push_back(w); // [] creates an empty vector the first time
}
for (const auto& [letter, group] : by_letter) {
std::cout << letter << ": ";
for (const auto& w : group) std::cout << w << ' ';
std::cout << '\n';
}
}a: apple avocado apricot
b: banana blueberry
c: cherryRange queries#
Because keys are sorted, a map can answer "the first key at least X" with lower_bound:
#include <iostream>
#include <map>
#include <string>
int main() {
std::map<int, std::string> grade_from = {{0, "F"}, {40, "D"}, {55, "C"}, {70, "B"}, {85, "A"}};
for (int marks : {92, 70, 38}) {
auto it = grade_from.upper_bound(marks); // first key greater than marks
--it; // the band that marks falls in
std::cout << marks << " -> " << it->second << '\n';
}
}92 -> A
70 -> B
38 -> FCustom key order#
By default, keys are compared with <. To sort differently, pass a comparator type, such as std::greater for descending order:
#include <functional>
#include <iostream>
#include <map>
#include <string>
int main() {
std::map<int, std::string, std::greater<int>> leaderboard = {
{820, "Ravi"}, {950, "Asha"}, {770, "Meera"},
};
for (const auto& [score, name] : leaderboard) {
std::cout << score << ' ' << name << '\n';
}
}950 Asha
820 Ravi
770 MeeraTo use your own type as a key, it needs a < (or a defaulted <=>; see Operator Overloading).
multimap#
A std::multimap allows repeated keys, for example several phone numbers for one person. It has no []; use insert and equal_range to get all values for a key.
map or unordered_map?#
Use std::unordered_map when you only need fast lookups, and std::map when you need the keys in order or range queries. See unordered_map.
Common mistakes#
Practice#
Practice exercise
Given a list of sales as pairs {"North", 1200}, {"South", 800}, {"North", 450}, {"East", 990}, {"South", 300}, total the sales per region with a std::map and print each region in alphabetical order, then the region with the highest total.
Show solution
#include <iostream>
#include <map>
#include <string>
#include <utility>
#include <vector>
int main() {
std::vector<std::pair<std::string, int>> sales = {
{"North", 1200}, {"South", 800}, {"North", 450}, {"East", 990}, {"South", 300},
};
std::map<std::string, int> totals;
for (const auto& [region, amount] : sales) {
totals[region] += amount;
}
std::string best;
int best_total = 0;
for (const auto& [region, total] : totals) {
std::cout << region << ": " << total << '\n';
if (total > best_total) {
best_total = total;
best = region;
}
}
std::cout << "Best: " << best << '\n';
}East: 990
North: 1650
South: 1100
Best: NorthKey takeaway#
Finished this lesson?