Jerome Baldridge Jerome Baldridge - 2 months ago 10
C++ Question

What is this use of std::map doing?

Can anyone explain the output I am getting from this simple program using

std::map
. Note that I insert
p
into the map, but not
q
yet it says it found them both, but also says there is only 1 element in the map!

#include <map>
#include <iostream>

struct screenPoint {
float x = 0, y = 0;
screenPoint(float x_, float y_): x{x_}, y{y_}{}
};

bool operator<(const screenPoint& left, const screenPoint& right){
return left.x<right.x&&left.y<right.y;
}

std::map<screenPoint, float> positions;

int main(int argc, const char * argv[]) {

auto p = screenPoint(1,2);
auto q = screenPoint(2,1);
positions.emplace(p,3);

auto f = positions.find(p);
auto g = positions.find(q);

if (f == positions.end()){
std::cout << "f not found";
} else {
std::cout << "f found";
}

std::cout << std::endl;

if (g == positions.end()){
std::cout << "g not found";
} else {
std::cout << "g found";
}

std::cout << std::endl;

std::cout << "number elements: " << positions.size() << "\n";
return 0;
}


Output:

f found
g found
number elements: 1

Answer

In order to use a data type in an std::map, it must have a particular ordering called a strict weak ordering (https://en.wikipedia.org/wiki/Weak_ordering). This means that the inequality operator (<) obeys a very specific set of rules. The operator you specified however is not a weak ordering. In particular, given two screenPoints, a and b constructed from (1,2) and (2,1) respectively, you will see that it is false both that a < b and that b < a. In a strict weak ordering, this would be required to imply that a == b, which is not true!

Because your inequality operator does not meet the requirement of a strict weak ordering, map ends up doing unexpected things. I recommend reading up more details on what this ordering is, and reading/thinking about why map requires it. In the short term, you can redefine your operator as follows:

bool operator<(const screenPoint& left, const screenPoint& right){
  if left.x < right.x return true;
  else return (left.y < right.y);
}
Comments