Sandy S Sandy S - 26 days ago 6
C++ Question

Why is Map[2] updating a wrong key data? Is this a proper way of doing this?

#include <iostream>
using namespace std;

struct ls{
bool operator()(int lhs, int rhs){
return lhs == rhs;
}
};

int main(){
map<int,string,ls> m1 {{1,"A"},{2,"B"}};
map<int,string>::iterator i;

for(i=m1.begin();i!=m1.end();++i) {
cout<<i->first<<" - "<<i->second<<endl;
}

//If we print data here only 1, "A" data is present.
m1[2] = "C";
for(i=m1.begin();i!=m1.end();++i) {
cout<<i->first<<" - "<<i->second<<endl;
}

//the above statement updates m1[1] as "C" even though we are m1[2]
}

Answer

The problem is that you are not respecting the contract of std::map third template argument which should be the comparison function.

The comparison function, which defaults to std::less<T>, must provide a total ordering on the keys of your std::map. For this purpose the ISO standard defines that, for associative containers at §23.2.4.3:

The phrase “equivalence of keys” means the equivalence relation imposed by the comparison and not the operator== on keys. That is, two keys k1 and k2 are considered to be equivalent if for the comparison object comp, comp(k1, k2) == false && comp(k2, k1) == false. For any two keys k1 and k2 in the same container, calling comp(k1, k2) shall always return the same value.

Now in your situation you define the comparison as lhs == rhs which means that

auto b1 = ls{}(1, 2);
auto b2 = ls{}(2, 1};

are both false, so both keys are considered an unique key (if a is not less than b and b is not less than a then a must be equal to b). This means that on map construction only the first pair is inserted.

But then with m1[2] = "C", since you are getting the reference to the value mapped to 2 and 2 compares equal to 1 according to your function, you update the only key present.