Free tutorials & notes in Hindi & English · Clean code examples · Mobile friendly learning
🔴 Advanced  ·  Lesson 57

set and map in STL

Written and reviewed by · Senior IT Faculty · 15+ years’ experience

The Ordered Associative Container Model

std::set and std::map are ordered associative containers. They retrieve data by a key and maintain iteration order through a comparison object. Default std::less<Key> normally gives ascending order.

ContainerStored valueKey policy
set<Key>Key itselfUnique
multiset<Key>Key itselfEquivalent keys allowed
map<Key,T>pair<const Key,T>Unique
multimap<Key,T>Key-value pairEquivalent keys allowed

Core search, insertion and erasure operations are logarithmic. The standard specifies behavior and complexity, not a mandatory red-black-tree implementation.

Choose from meaning: set answers “is this unique key present?” Map answers “which value belongs to this key?” For a combined design comparison, read vector versus map.

std::set: Unique Ordered Values

#include <set>

std::set<int> roll_numbers{104, 101, 104, 103};

for (int roll : roll_numbers) {
    std::cout << roll << ' ';
}
101 103 104

The duplicate 104 is not inserted, and iteration follows key order. Inspect the insertion result:

auto [position, inserted] = roll_numbers.insert(102);
if (inserted) {
    std::cout << "Added " << *position;
}

A set iterator provides const access to the key because changing a key in place could break the ordering invariant. To change a key, erase the old element and insert the new one. Since C++17, node handles can support carefully controlled extraction and reinsertion.

Use multiset when repeated equivalent values are part of the model, such as all marks including duplicates. Do not use a set merely as a convenient duplicate remover if the original order must remain significant.

std::map: Unique Keys with Values

#include <map>
#include <string>

std::map<std::string, int> marks{
    {"Sara", 91}, {"Aman", 78}
};

marks.insert_or_assign("Aman", 83);
marks.try_emplace("Kabir", 84);

for (const auto& [name, mark] : marks) {
    std::cout << name << ':' << mark << ' ';
}
Aman:83 Kabir:84 Sara:91

insert_or_assign inserts a missing key or replaces its mapped value. try_emplace inserts only when the key is absent and can avoid constructing a mapped object unnecessarily. Plain insert does not replace an existing key.

The key is const through the iterator; the mapped value is modifiable:

for (auto& [name, mark] : marks) {
    mark += 2;       // allowed
    // name = "X";  // not allowed: key is const
}

Lookup, Access and Range Queries

OperationResultInserts?
find(key)Iterator or end()No
contains(key) C++20BooleanNo
count(key)0/1 for set/mapNo
map::at(key)Mapped reference or exceptionNo
map::operator[]Mapped referenceYes, if missing
lower_bound(key)First element not before keyNo
upper_bound(key)First element after keyNo
equal_range(key)Both range boundariesNo
if (auto it = marks.find("Sara"); it != marks.end()) {
    std::cout << it->second;
}

if (!marks.contains("Riya")) { // C++20
    std::cout << "Not found";
}
Silent mutation: if (marks["Riya"] == 0) inserts Riya when absent. Use find or contains for a read-only existence test.

Comparators, Equivalence and Custom Keys

The comparison must impose a strict weak ordering. Two keys are equivalent when neither compares before the other; this equivalence is not necessarily identical to operator==.

struct ByLengthThenText {
    bool operator()(const std::string& a,
                    const std::string& b) const {
        if (a.size() != b.size()) return a.size() < b.size();
        return a < b;
    }
};

std::set<std::string, ByLengthThenText> words;

Do not use <=, a random result, current time or mutable external state. The comparator must remain consistent while keys are stored.

For a custom record key, define a stable comparator over the fields that form identity. C++20 transparent comparators such as std::less<> can permit heterogeneous lookup without constructing a temporary key when the involved comparisons are supported.

std::map<std::string, int, std::less<>> scores;
// scores.find(std::string_view{"Sara"}); // heterogeneous lookup

Insertion, Erasure and Iterator Safety

marks.emplace("Riya", 86);
marks.erase("Aman");

for (auto it = marks.begin(); it != marks.end(); ) {
    if (it->second < 40) it = marks.erase(it);
    else ++it;
}
  • Insertion and emplacement do not invalidate existing iterators or references.
  • Erasure invalidates only iterators and references to erased elements.
  • erase(iterator) returns the following iterator, enabling a safe erase loop.
  • Do not dereference end() or reuse an erased iterator.

A good position hint can make insertion more efficient, but a wrong hint does not change correctness. Bulk-load sorted data only after measuring; clear code is the first priority.

Unlike unordered_map, map supplies key order and logarithmic worst-case operations. Unordered containers offer average constant lookup but no sorted iteration and can have linear worst cases.

Complete Word-Frequency Lab with Output

#include <iostream>
#include <map>
#include <set>
#include <string>
#include <vector>

int main() {
    const std::vector<std::string> words{
        "code", "learn", "code", "cpp", "learn", "code"
    };

    std::set<std::string> unique_words;
    std::map<std::string, int> frequency;
    for (const std::string& word : words) {
        unique_words.insert(word);
        ++frequency[word]; // insertion with zero is intentional
    }

    std::cout << "Unique:";
    for (const auto& word : unique_words) std::cout << ' ' << word;
    std::cout << "\nFrequency:\n";
    for (const auto& [word, count] : frequency) {
        std::cout << word << '=' << count << '\n';
    }
}
Unique: code cpp learn Frequency: code=3 cpp=1 learn=2

Here operator[] is appropriate: a missing word should begin with an integer value of zero before incrementing. Both containers iterate in lexical key order.

Common Mistakes, Practice and Review

MistakeCorrection
Expecting insertion orderExpect comparator order
map[key] for read-only lookupUse find/contains/at
Expecting duplicate keysUse multi-container or redesign value
Comparator uses <=Provide strict weak ordering
Changing key through iteratorErase/reinsert or node-handle workflow
Using erased iteratorUse returned next iterator
Assuming a particular treeRely on standard guarantees only

Practice: build a phone book, word counter, unique roll-number register, score range query with lower_bound, and a custom key for year/roll number. Test empty data, missing keys, duplicate insertion and erasure during traversal.

  1. Is the data a set or key-value relation?
  2. Are keys unique or repeatable?
  3. Is comparator equivalence correct?
  4. Can lookup accidentally insert?
  5. Is the required order explicit?
  6. Are erased handles discarded?

Authoritative References

Ordering, key equivalence, complexity and iterator rules were checked against the current working draft. Review STL architecture for the full container decision table.

Ordered Associative Container Model

set और map key द्वारा data retrieve करते और comparator से order maintain करते हैं। Default std::less normally ascending order देता है।

ContainerDataKeys
setKeyUnique
multisetKeyEquivalent allowed
mappair<const Key,T>Unique
multimapKey-valueEquivalent allowed

Core search/insert/erase O(log n) हैं। Standard specific tree mandate नहीं करता। vector vs map decision guide देखें।

std::set: Unique Ordered Values

std::set<int> rolls{104,101,104,103};
for(int roll:rolls) std::cout<<roll<<' ';
auto [pos,inserted]=rolls.insert(102);
101 103 104

Duplicate 104 insert नहीं हुआ। Set iterator key को const access देता है; in-place change ordering तोड़ सकता है। Key बदलने के लिए erase/reinsert करें। Repeated equivalent values चाहिए तो multiset लें।

std::map: Unique Key और Value

std::map<std::string,int> marks{
 {"Sara",91},{"Aman",78}};
marks.insert_or_assign("Aman",83);
marks.try_emplace("Kabir",84);
for(const auto& [name,mark]:marks)
 std::cout<<name<<':'<<mark<<' ';
Aman:83 Kabir:84 Sara:91

insert_or_assign insert या replace करता है; try_emplace missing key पर ही construct करता है। Iterator में key const लेकिन mapped value modifiable है।

Lookup और Access

OperationResultInsert?
findIterator/endNo
contains C++20boolNo
count0/1No
atValue/exceptionNo
operator[]Mapped referenceMissing पर yes
lower_boundNot-before keyNo
if(auto it=marks.find("Sara");it!=marks.end())
 std::cout<<it->second;
if(!marks.contains("Riya")) std::cout<<"Not found";
Read-only test में marks["Riya"] use करने से missing key insert हो जाएगी।

Comparators और Key Rules

Comparator strict weak ordering दे। दो keys equivalent हैं जब कोई भी दूसरे से पहले compare न हो; यह जरूरी नहीं कि == जैसा हो।

struct ByLengthThenText{
 bool operator()(const std::string& a,
                 const std::string& b)const{
  if(a.size()!=b.size()) return a.size()<b.size();
  return a<b;
 }
};

<=, random result, time या mutable state comparator में गलत हैं। Stored keys के दौरान result consistent रहे।

Insertion, Erasure और Iterator Safety

marks.emplace("Riya",86);
marks.erase("Aman");
for(auto it=marks.begin();it!=marks.end();){
 if(it->second<40) it=marks.erase(it);
 else ++it;
}
  • Insert/emplace existing handles invalidate नहीं करते।
  • Erase केवल erased element handles invalidate करता है।
  • erase(iterator) next iterator देता है।
  • end को dereference और erased iterator reuse न करें।

unordered_map average O(1) lookup दे सकता है लेकिन sorted order नहीं और worst O(n) संभव है।

Complete Word-Frequency Lab

std::vector<std::string> words{
 "code","learn","code","cpp","learn","code"};
std::set<std::string> unique_words;
std::map<std::string,int> frequency;
for(const std::string& word:words){
 unique_words.insert(word);
 ++frequency[word];
}
Unique: code cpp learn Frequency: code=3 cpp=1 learn=2

यहां [] intentional है क्योंकि missing count zero से शुरू होकर increment होना चाहिए। दोनों containers lexical key order में iterate करते हैं।

Mistakes, Practice और Review

MistakeCorrection
Insertion order expectComparator order
Read lookup में []find/contains/at
Duplicate keys expectMulti-container/model
Comparator <=Strict weak ordering
Key in-place changeErase/reinsert
Erased iterator useReturned next iterator

Practice: phone book, word counter, unique roll register, lower_bound score query और custom year/roll key बनाएं।

  1. Set या relation?
  2. Unique/repeated keys?
  3. Comparator valid?
  4. Lookup inserts?
  5. Required order?
  6. Erased handles discarded?

Authoritative संदर्भ

Order, equivalence, complexity और iterator rules current draft से verified हैं। STL architecture भी पढ़ें।

अक्सर पूछे जाने वाले प्रश्न (FAQ)

C++ set और map में क्या अंतर है?
set unique keys को elements की तरह रखता है। map unique ordered key के साथ mapped value जोड़ता है। दोनों comparison object से order maintain करते हैं।
क्या std::set और std::map हमेशा sorted होते हैं?
Iteration container comparator के order में होती है; default std::less normally ascending key order देता है। Valid custom strict weak ordering इसे बदल सकता है।
Missing key पर map operator[] क्या करता है?
यह उस key के लिए value-initialized mapped value insert करके reference लौटाता है। Read-only lookup में find, contains या at लें।
क्या set या map duplicate keys रख सकता है?
set और map unique keys रखते हैं। Equivalent keys के लिए multiset/multimap या map> जैसा suitable model चुनें।
क्या insertion set/map iterators invalidate करता है?
Normal insert/emplace existing iterators/references invalidate नहीं करता। Erase केवल erased elements के handles invalidate करता है।
← Back to C++ Tutorial
🔗

Share this topic with a friend

यह topic किसी दोस्त को भेजें

Found it useful? Send it to a classmate learning the same thing.

अच्छा लगा? जो दोस्त यही सीख रहा है, उसे भेज दीजिए।