使用 std::map 时,我应该为键类型重载 operator== 吗?

Posted

技术标签:

【中文标题】使用 std::map 时,我应该为键类型重载 operator== 吗?【英文标题】:When using std::map should I overload operator== for the key type? 【发布时间】:2013-11-23 21:34:37 【问题描述】:

std::map 不应该有重复的键,所以当我有自定义类型时它如何知道我有重复的键,我是否需要重载重载运算符 ==?还是会隐式创建?

根据文档,我只需要操作符

考虑这个例子:

class MyType
public:
  MyType(int newId)
    id = new int;
    *id = newId;
  ;
  ~MyType
    delete id;
  
private:
  int* id;
;

int main()
  std::map<MyType,int> myMap;

  std::pair<std::map<MyType,int>::iterator,bool> ret;
  ret = myMap.insert ( std::pair<MyType,int>(myType(2),100) );

  if (!ret.second) //now how can he knows that?
    std::cout << "element already existed" << endl;
  

【问题讨论】:

您的类型MyType 违反了三/五规则。这里不需要动态分配。 我知道这只是作为一个例子。这不是重点…… 【参考方案1】:

std::map 不关心键的文字 unicity。它关心键等价。当 a &lt; bb &lt; a 都不为真时,键 ab 根据定义是等效的。

还要注意std::map 不直接使用operator &lt;std::mapoperator &lt; 一无所知。而std::map 使用比较谓词,其类型被指定为std::map 模板的第三个参数。该参数的默认值为std::lessstd::less 的实现将比较委托给operator &lt;(除非专门化不同)。这就是operator &lt; 发挥作用的方式。但您始终可以提供自己的谓词,不一定使用operator &lt;

但无论如何,这里的关键时刻是std::map 使用排序的“更少”比较并且仅使用“更少”比较。它不需要也不关心任何“平等”比较。

与此同时,std::unordered_map 将是另一回事。它依赖于谓词指定的无序“相等”比较。默认为std::equal_tostd::equal_to 的实现将调用委托给 operator ==(除非专门化不同)。

【讨论】:

需要注意的是,C++20 移除了除相等运算符之外的委托map 比较运算符,并用宇宙飞船运算符&lt;=&gt; 替换它们。 @David G:你到底指的是什么?据我所知,在 C++20 中,std::map 仍然使用 std::less,而主要的 std::less 模板仍然使用 &lt;。确实,在 C++20 中,&lt; 可以隐式派生自 &lt;=&gt;,但这是一个不同的主题,与 std::map 无关。 我指的是 std::map 在 C++20 之前使用的一组比较运算符(除了相等运算符)(例如 template&lt; class Key, class T, class Compare, class Alloc &gt; bool operator!=( const std::map&lt;Key,T,Compare,Alloc&gt;&amp; lhs, const std::map&lt;Key,T,Compare,Alloc&gt;&amp; rhs ); 现在已包含在宇宙飞船中映射的值类型的运算符,然后从它综合运算符。std::less 将使用&lt;,除非指定为模板参数。对于可能会感到惊讶的人来说,这只是一个仅供参考通过新的行为。【参考方案2】:

运算符

【讨论】:

哦,当然是的,谢谢,所以即使我自己实现了 operator== 也会被忽略? 是的,map的实现只使用了 @Jasper:实际上,equalitynever 检查的!检查的是等价!没关系?好吧,考虑一个由std:pair&lt;int, int&gt; 组成的键,其中只有first 组件用于排序比较:对象可能不相等,但它们仍然可以被认为是等效的。 当然,要检查的是你的操作符 等效确实是一个更好的名称【参考方案3】:

你应该重载operator&lt;

std::map 将使用 !(a &lt; b) &amp;&amp; !(b &lt; a) 作为唯一性测试。

【讨论】:

【参考方案4】:

顺序关联容器仅使用严格的弱顺序来识别它们的键。他们不会使用operator==()。用于定位对象的唯一比较是 std::map&lt;K, V, Compare, Allocator&gt; 的第三个模板参数。

比较用于将键分组为等价集。如果k1 不小于k2k2 不小于k1,则两个键k1k2 被认为是等价的:

bool equivalent = !(k1 < k2) && !(k2 < k1);

当然,关联容器实际上会使用类似的东西

!predicate(k1, k2) && !predicate(k2, k1)

【讨论】:

以上是关于使用 std::map 时,我应该为键类型重载 operator== 吗?的主要内容,如果未能解决你的问题,请参考以下文章

被 const 逼入绝境:std::map::find() const 重载

基础结构体重载,用 char*作为std::map中的key

锁定 std::map C++

CLion 无法解析类型 std::unordered_map 即使它提示我包含标题并且编译工作

获取在运行时作为参数传递的重载函数的名称

SWIG:使用带有 shared_ptr 的 std::map 访问器?