std::map 不删除带有自定义对象的重复项

std::map not removing duplicates with custom object

本文关键字:对象 自定义 map 删除 std      更新时间:2023-10-16

all.

因此,我创建了一个可比较基类(a la Java(,它完成了重载C++比较运算符的工作。在这里:

template <class T>
class Comparable {
public:
  bool operator== (const T& rhs) const { return this->compare(rhs) == 0; }
  bool operator!= (const T& rhs) const { return !(*this == rhs); }
  bool operator<  (const T& rhs) const { return this->compare(rhs) < 0; }
  bool operator<= (const T& rhs) const { return (*this == rhs) || (*this < rhs); }
  bool operator>  (const T& rhs) const { return this->compare(rhs) > 0; }
  bool operator>= (const T& rhs) const { return (*this == rhs) || (*this > rhs); }
protected:
  virtual int compare (const T& rhs) const = 0;
};

子类对象既有 ID,也有需要作为排序键的数据。我已经实现了每个,以便具有相同 ID 的对象返回 0,如果它们不是相同的 ID,它们会根据其数据进行排序。下面是一个示例:

int Foo::compare(const Foo& rhs) const
{
    if (_id == rhs._id)
        return 0;
    // _value is integer data; comparison should sort on this
    if (_value == rhs._value)
    {
        // OK, same data, now sort on ID's
        return _id.compare(rhs._id);
    }
    // Sort on value
    return _value - rhs._value;
}

到目前为止,我认为一切都很好。

但是,当我尝试将Foo对象存储在std::set容器中时,该集合不会消除重复项。也就是说,其中仍然会有包含相同 ID 的对象,即使这应该被视为相等。

有谁知道发生了什么?

编辑:关于为什么代码以这种方式设计有很多问题。

我需要满足两个条件:

  1. 无论值如何,具有相同 ID 的对象都必须被视为"相同"对象。
  2. 不具有相同 ID 的对象必须根据其值进行排序(该值是什么,取决于对象的类型(。

这是因为创建这些对象的数据来自未经验证的来源。如果该源提供的数据具有相同的 ID 但值不同,则为无效数据。

编辑2:关于std::map的严格弱排序。假设您有两个 Foo 对象,A 和 B。

如果他们的ID相等,那么A<B是假的,B><A是假的。如果它们的>

这不应该满足严格的订购规则吗?

无论如何,如果 std::set 使用小于运算符(默认情况下这样做(,它不应该按设计工作吗?

编辑3:std::set,而不是std::map。那真是太愚蠢了。道歉。

std::map不会通过operator==确定重复项。它使用operator< 1,因为它无论如何都需要使用它来确定顺序。你的operator<坏了。它需要强制执行严格的弱排序。

比较失败的方式在以下属性中(称为传递性(。对于 3 个对象,如果 A < BB < C ,那么一定是A < C .

因此,请考虑三个对象,ABCA.id != B.id,但A.value < B.value,所以A < B。现在,C.id == B.id(因此C.id != A.id(,但C.value < A.value.所以C < AA < B.因此,C应该是< B的。但事实并非如此,因为C.id == B.id.

一种方法是像这样定义compare函数:

int Foo::compare(const Foo& rhs) const
{
    if (_id < rhs._id)
        return -1;
    if (rhs._id < _id)
        return 1;
    return _value - rhs._value;
}

如果您不能使用它,并且找不到其他方法来强制执行正确的排序,那么您根本无法将对象用作std::map中的键。

1.如果rhs不小于lhs,

并且lhs不小于rhs,则暗示它们是相等的。您还可以提供替代函子,只要它还强制执行严格的弱排序。

如果你没有严格的弱排序,你就不能使用map,如果你这样做了,你不能抱怨,它不起作用。这是map的先决条件。

编辑:

您的compare不会实现您指定的语义 - 如果在第二次测试中_value == rhs._value,则应返回 0。

但是有了这个修复,你仍然没有一个一致的排序 - 参见本杰明林德利在评论中给出的例子。从本质上讲,您的排序没有意义 - 您要么需要修复语义,要么停止使用需要一致排序的标准库组件。