BUG 描述
记录一个纠结了一天的 BUG:
向 set 容器中添加自定义类, 然后发现并没有添加进去, 真的是头大, 排查发现告诉我已经有相同 key 值元素存在了, 可我明明两个值不同
set / map 的 insert / emplace 的返回值
c++11 标准引入了 emplace, 与 insert 相对应. empalce 操作构造而不是拷贝元素。
- 当我们调用 insert 时, 我们将元素类型的对象传递给它们, 这些类型被拷贝到容器中
- 当我们调用 emplace, 会在容器管理的内存空间内直接创建对象。
注: - emplace 的参数根据元素的类型变化, 参数必须与元素类型的构造函数相匹配
- insert 和 emplace 只有在关键值 key 在容器中不存在时, 才会把该元素插入容器中, 否则如果容器中有关键值为 key 元素, 则什么也不做
- insert 和 emplace 的返回值是一个 pair, 它的 first 是一个迭代器 指向具有给定关键字的元素 second 是一个 bool 指出元素是否插入成功
因为当时 emplace 失败时也并没有抛异常, 但是这个返回值中的 bool 值为 false 告诉了我就是没有插入进去
set / map 的去重
在自定义类中重载 < 操作符, 或者重载 () 运算符
当时想的比较简单, 因为我的需求只是按时间排序, 所以就简单地写成了这种形式
bool operator<(const A& t) const
{
return val < t.v(); //比较两个对象中的时间值, 小的就在前
}
于是 BUG 就诞生了 :
set / map 的在判定你插入的元素是否和已有元素相等时, 是将其分别作为左操作数和右操作数, 而容器中元素分别作为右操作数和左操作数来进行比较, 如果两次返回值都为 false, 那么认为两个元素相等, 如果两次都返回 true, 则行为未定义
所以相同元素比较一定返回的是 false
而虽然我插入的对象其他值不同, 但是当比较的时间值相同时, 就被 set 认为是 key 值相同的同一元素从而不会插入了, 也因此并没有发生异常行为不会抛异常
strict weak ordering
C++ STL 容器要求 : strict weak ordering (严格弱序化)
就是说
A > B 和 B > A 不能同时为真
STL 容器判断等价:
!(A < B) && !(B < A) 成立时为等价
这也是上面说的为什么要遵循相同元素比较返回的一定是 false
如果是 return A <= B
那么你会发现假如 A B等价, 那么上式为 false
!!!
以后写比较函数的时候一定要考虑完善, 不能想的过于简单