Maps & Sets in C++

    Atul Kabra4 min readUpdated

    A std::map stores key-value pairs so you can look up a value by a meaningful key, and a std::set stores a collection of unique values with fast membership tests. Where a vector finds things by position, maps and sets find things by content. Reach for a map when you want "given this name, what is the score?" and a set when you want "have I seen this value before?"

    Here is each, with the ordered and unordered variants.

    std::map — key-value lookups

    Include <map>. A map keeps its keys sorted and stores one value per key.

    #include <iostream>
    #include <map>
    #include <string>
    
    int main() {
        std::map<std::string, int> scores;
    
        scores["Asha"] = 95;          // insert or update
        scores["Ravi"] = 72;
        scores["Meera"] = 88;
    
        std::cout << "Asha: " << scores["Asha"] << "\n";  // 95
    
        // iterate in sorted key order
        for (const auto& [name, score] : scores) {
            std::cout << name << " -> " << score << "\n";
        }
    }
    

    Output (keys come out sorted):

    Asha: 95
    Asha -> 95
    Meera -> 88
    Ravi -> 72
    

    The structured binding const auto& [name, score] cleanly unpacks each pair.

    Looking up safely

    scores["Unknown"] has a surprising side effect: if the key is missing, it inserts it with a default value (0 for int). To check without inserting, use find or contains.

    #include <map>
    #include <string>
    #include <iostream>
    
    int main() {
        std::map<std::string, int> scores{{"Asha", 95}};
    
        // C++20: contains() — does not insert
        if (scores.contains("Ravi")) {
            std::cout << "Ravi found\n";
        } else {
            std::cout << "Ravi not found\n";
        }
    
        // find() returns an iterator; end() means "not present"
        if (auto it = scores.find("Asha"); it != scores.end()) {
            std::cout << it->first << " = " << it->second << "\n";
        }
    }
    

    std::set — unique values

    Include <set>. A set stores each value at most once, sorted, and answers "is this here?" quickly.

    #include <iostream>
    #include <set>
    
    int main() {
        std::set<int> seen;
    
        seen.insert(5);
        seen.insert(2);
        seen.insert(5);          // duplicate ignored
    
        std::cout << "size: " << seen.size() << "\n";   // 2
        std::cout << "has 2? " << seen.contains(2) << "\n"; // 1 (true)
    
        for (int v : seen) {     // iterates in sorted order: 2 5
            std::cout << v << " ";
        }
        std::cout << "\n";
    }
    

    Want to learn this properly?

    Join the waitlist for our courses — beginner-friendly, project-first classes in Jalgaon.

    Browse courses

    Ordered vs unordered

    std::map / std::set keep keys sorted (logarithmic-time operations, backed by a balanced tree). Their cousins std::unordered_map / std::unordered_set use hashing for average constant-time lookups but no ordering.

    • Need elements in sorted order, or range queries? Use std::map / std::set.
    • Just need fast lookup and do not care about order? Use std::unordered_map / std::unordered_set.

    A practical pattern: counting frequencies

    A map shines when you need to count how often each thing appears — words in a sentence, marks in a class, votes in a poll. The default-insert behaviour of [] actually helps here, because a missing key starts at 0 and is then incremented.

    #include <iostream>
    #include <map>
    #include <string>
    
    int main() {
        std::map<std::string, int> wordCount;
        for (const std::string& word : {"a", "b", "a", "c", "b", "a"}) {
            ++wordCount[word];   // missing keys start at 0, then increment
        }
    
        for (const auto& [word, count] : wordCount) {
            std::cout << word << ": " << count << "\n";
        }
    }
    

    Output (sorted by key):

    a: 3
    b: 2
    c: 1
    

    The same pattern with std::unordered_map runs faster on large inputs but prints the words in no particular order. Choose based on whether you need the sorted output.

    Common mistakes

    • Using [] to check if a key exists. m["x"] inserts "x" if it is missing. Use contains() or find() for a pure lookup.
    • Expecting unordered_map to be sorted. It is not — only the ordered map/set keep keys in order.
    • Inserting duplicate keys into a map. m["k"] = 1; m["k"] = 2; keeps only the last value; maps store one value per key.
    • Dereferencing the result of find() without checking. Compare against end() first; it signals "not found."

    FAQ

    When should I use a map versus a vector? Use a map when you look things up by a key (a name, an ID). Use a vector when you access by position or just need an ordered list.

    What is the difference between map and unordered_map? map keeps keys sorted and offers logarithmic-time operations; unordered_map uses hashing for average constant-time lookups but does not keep any order.

    Keep learning

    Build real programs with the STL alongside mentors in Jalgaon — join the waitlist for our C++ Programming course.

    Want to learn this properly?

    Join the waitlist for our courses — beginner-friendly, project-first classes in Jalgaon.

    Browse courses
    Atul Kabra

    Founder, Infoplanet

    Atul Kabra founded Infoplanet in 2001 and has spent over two decades teaching programming — C, C++, Java, databases and more — to students across Maharashtra.

    Related guides