Search code examples
c++pointersstlunordered-mapunordered-set

C++ Updating values in a unordered_map, where the data type of key-value pair is int-unordered_set


I was solving a DSA question and observed a slightly strange behavior in the C++ standard template library:

    vector<int> v = {1, 7, 8, 3, 12};

    unordered_map<int, unordered_set<int>> ump;

    for (int i=0; i<v.size(); i++) {
        unordered_set<int> us;
        us.insert(56);
        ump.insert(mp(v[i], us));
    }
    
    for (int i=0; i<v.size(); i++) {
        unordered_set<int> us = ump.find(v[i])->second;
        us.insert(67);
    }

    for (auto it = ump.begin(); it != ump.end(); it++) {
        cout << it->first << ": ";
        for (auto ait = it->second.begin(); ait!=it->second.end(); ait++) {
            cout << *ait << ' ';
        }
        cout << '\n';
    }

Here the output is coming to be:

12: 56 
3: 56 
8: 56 
7: 56 
1: 56 

But the expected output should be:

12: 67 56 
3: 67 56 
8: 67 56 
7: 67 56 
1: 67 56

And I guess the problem is arising during the insertion of values into the set. And I also think, the problem is in someway related to the "changing values through their reference". But not exactly sure what is causing this. I experimented a bit more and found that the below code snippet works. But still not sure, what is going wrong in the above code ?

In the below code snippet, instead of directly updating the set through its reference, I made a copy of it. Then inserted my values and again copied that into the map, and it worked.

    vector<int> v = {1, 7, 8, 3, 12};

    unordered_map<int, unordered_set<int>> ump;

    for (int i=0; i<v.size(); i++) {
        unordered_set<int> us;
        us.insert(56);
        ump.insert(mp(v[i], us));
    }
    
    for (int i=0; i<v.size(); i++) {
        unordered_set<int> us = ump.find(v[i])->second;
        unordered_set<int> us1;
        for (auto it = us.begin(); it!=us.end(); it++) {
            us1.insert(*it);
        }
        us1.insert(67);
        ump.find(v[i])->second = us1;
    }

    for (auto it = ump.begin(); it != ump.end(); it++) {
        cout << it->first << ": ";
        for (auto ait = it->second.begin(); ait!=it->second.end(); ait++) {
            cout << *ait << ' ';
        }
        cout << '\n';
    }

Here the output is exactly equal to the expected one:

12: 67 56 
3: 67 56 
8: 67 56 
7: 67 56 
1: 67 56 

Solution

  • unordered_set<int> us = ump.find(v[i])->second;
    

    Makes a copy of the set so your modifications don't change the value in ump. You need to use a reference instead:

    unordered_set<int>& us = ump.find(v[i])->second;
    

    Or using auto:

    auto& us = ump.find(v[i])->second;