Skip to content
Laviyx Learn

Try

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.

Intermediate13 min readUpdated
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#

C++
#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";
}
Output
Asha: 21
Meera: 23
Ravi: 26
3 people

The 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:

C++
#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';
}
Output
0
2

[] also cannot be used on a const map. For lookups, use the methods below.

Looking up safely#

C++
#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";
    }
}
Output
coffee costs 35
false
juice is not on the menu
MethodIf the key is missing
m[key]Inserts a default value
m.at(key)Throws std::out_of_range
m.find(key)Returns m.end()
m.contains(key) (C++20)Returns false
m.count(key)Returns 0 (1 if present)

Use 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:

C++
#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';
}
Output
true false
asha@example.com
asha.rao@example.com

Erasing#

C++
#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';
}
Output
1A 3C

Counting and grouping#

Two very common patterns: counting occurrences, and grouping items under a key:

C++
#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';
    }
}
Output
a: apple avocado apricot
b: banana blueberry
c: cherry

Range queries#

Because keys are sorted, a map can answer "the first key at least X" with lower_bound:

C++
#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';
    }
}
Output
92 -> A
70 -> B
38 -> F

Custom key order#

By default, keys are compared with <. To sort differently, pass a comparator type, such as std::greater for descending order:

C++
#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';
    }
}
Output
950 Asha
820 Ravi
770 Meera

To 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?#

std::mapstd::unordered_map
OrderSorted by keyNo particular order
LookupO(log n)O(1) on average
Range queries (lower_bound)YesNo
Key needs<a hash and ==

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
C++
#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';
}
Output
East: 990
North: 1650
South: 1100
Best: North

Key takeaway#

Finished this lesson?