How does the compare function in std::map in C++ work if it is reflexively true?

ⅰ亾dé卋堺 提交于 2020-05-25 08:27:28

问题


I have a map in my project. Every time I insert a new element, I want to ensure that the key of the new element I insert is at least a minimum width apart from other elements in the map. To do this I wrote a custom compare class like this:

class PulseCompare
{
public:
    PulseCompare(int minwidth_):minwidth(minwidth_){};
    bool operator()(const int x, const int y) const {
        if(abs(x-y)>minwidth) return false;
        else return true;
    }
private:
    int minwidth;
};

and created the map like this:

std::map<int,float,PulseCompare> pulsemap(PulseCompare(256));

and before I insert an element I use the map.find method like this:

if ( pulsemap.find(1600) == pulsemap.end() ) {
  // not found so I can insert
} else {
  // found
}

But the problem is that when map tries to reflexively compare using the above compare function by interchanging the values of x and y, it would get a true for both the cases which is usually not the case with normal comparison operators like < and >

On the cplusplus documentation page on std::map::key_comp here it says and I quote

The comparison object of a map object is set on construction. Its type (member key_compare) is the third template parameter of the map template. By default, this is a less object, which returns the same as operator "<".

This object determines the order of the elements in the container: it is a function pointer or a function object that takes two arguments of the same type as the element keys, and returns true if the first argument is considered to go before the second in the strict weak ordering it defines, and false otherwise.

Two keys are considered equivalent if key_comp returns false reflexively (i.e., no matter the order in which the keys are passed as arguments).

But this does not say about a case where it is reflexively true. Can anyone tell me what will be its behaviour then? Or should I do this interval comparison only by iterating over the entire map?


回答1:


Why not just use this as your comparator?

return minwidth < (y - x);

Here is a working example: http://coliru.stacked-crooked.com/a/e115d3a2f6714773




回答2:


  1. The comparator that is used in std::map must provide a strict weak ordering of the objects.
  2. Your comparator does not.
  3. Therefore, your instance of std::map will produce undefined behavior.

Note: It's generally easier to just have the comparator provide a total ordering.

Additionally, let's describe what a strict weak ordering requires. Here, I'm taking excerpts from C++ 2011, Section 25.4.

  • You're going to create a functor Compator comp; I'm going to refer to comp(lhs, rhs) as a function that returns a boolean. It's helpful to think of it as lhs < rhs.
  • We're going to create a function equiv(lhs, rhs). This is defined as (!comp(lhs, rhs) && !comp(rhs, lhs)). So, !(lhs < rhs) && !(rhs < lhs).

We're required to have the following rules hold:

comp(a, b) && comp(b, c) implies comp(a, c)
equiv(a, b) && equiv(b, c) implies equiv(a, c)



回答3:


Actually if you rewrite your comparator this way, it should work:

bool operator()(const int x, const int y) const {
    if(abs(x-y)<=minwidth) return false;
    else return x < y;
}

And you do not need to use find before inserting, you are doing double work. Just try to insert, if such key exists map will reject that insertion. std::map::insert also returns std::pair<iterator,bool> so you can check if insertion was successful or not.



来源:https://stackoverflow.com/questions/24689092/how-does-the-compare-function-in-stdmap-in-c-work-if-it-is-reflexively-true

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!