使用 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 < b
和 b < a
都不为真时,键 a
和 b
根据定义是等效的。
还要注意std::map
不直接使用operator <
。 std::map
对 operator <
一无所知。而std::map
使用比较谓词,其类型被指定为std::map
模板的第三个参数。该参数的默认值为std::less
。 std::less
的实现将比较委托给operator <
(除非专门化不同)。这就是operator <
发挥作用的方式。但您始终可以提供自己的谓词,不一定使用operator <
。
但无论如何,这里的关键时刻是std::map
使用排序的“更少”比较并且仅使用“更少”比较。它不需要也不关心任何“平等”比较。
与此同时,std::unordered_map
将是另一回事。它依赖于谓词指定的无序“相等”比较。默认为std::equal_to
。 std::equal_to
的实现将调用委托给 operator ==
(除非专门化不同)。
【讨论】:
需要注意的是,C++20 移除了除相等运算符之外的委托map
比较运算符,并用宇宙飞船运算符<=>
替换它们。
@David G:你到底指的是什么?据我所知,在 C++20 中,std::map
仍然使用 std::less
,而主要的 std::less
模板仍然使用 <
。确实,在 C++20 中,<
可以隐式派生自 <=>
,但这是一个不同的主题,与 std::map
无关。
我指的是 std::map
在 C++20 之前使用的一组比较运算符(除了相等运算符)(例如 template< class Key, class T, class Compare, class Alloc > bool operator!=( const std::map<Key,T,Compare,Alloc>& lhs, const std::map<Key,T,Compare,Alloc>& rhs );
现在已包含在宇宙飞船中映射的值类型的运算符,然后从它综合运算符。std::less
将使用<
,除非指定为模板参数。对于可能会感到惊讶的人来说,这只是一个仅供参考通过新的行为。【参考方案2】:
运算符
【讨论】:
哦,当然是的,谢谢,所以即使我自己实现了 operator== 也会被忽略? 是的,map的实现只使用了 @Jasper:实际上,equality 是 never 检查的!检查的是等价!没关系?好吧,考虑一个由std:pair<int, int>
组成的键,其中只有first
组件用于排序比较:对象可能不相等,但它们仍然可以被认为是等效的。
当然,要检查的是你的操作符 等效确实是一个更好的名称【参考方案3】:
你应该重载operator<
。
std::map
将使用
!(a < b) && !(b < a)
作为唯一性测试。
【讨论】:
【参考方案4】:顺序关联容器仅使用严格的弱顺序来识别它们的键。他们不会使用operator==()
。用于定位对象的唯一比较是 std::map<K, V, Compare, Allocator>
的第三个模板参数。
比较用于将键分组为等价集。如果k1
不小于k2
或k2
不小于k1
,则两个键k1
和k2
被认为是等价的:
bool equivalent = !(k1 < k2) && !(k2 < k1);
当然,关联容器实际上会使用类似的东西
!predicate(k1, k2) && !predicate(k2, k1)
【讨论】:
以上是关于使用 std::map 时,我应该为键类型重载 operator== 吗?的主要内容,如果未能解决你的问题,请参考以下文章
被 const 逼入绝境:std::map::find() const 重载
基础结构体重载,用 char*作为std::map中的key