【问题标题】:How to provide comparison function in std::set for unique element insertion?如何在 std::set 中为唯一元素插入提供比较功能?
【发布时间】:2015-11-05 14:32:51
【问题描述】:

我有以下用户定义的类,

class simple
{
public:
  simple(string str1, string str2)
   : s1(str1)
   , s2(str2)
  {
  }
  const string& getS1() const {return s1;}
  const string& getS2()const {return s2;} 
  bool operator<(const simple& s) {
    return strcmp(this->getS1().c_str(), s.getS1().c_str()) < 0 && strcmp(this->getS2().c_str(), s.getS2().c_str()) < 0;
  }
private:
  const string s1;
  const string s2;
}

我将这个类存储在 std::set 中,如下所示:

std::set<simple*> mySimplePtrSet;
simple* s1 = new simple("stack", "overflow");
simple* s2 = new simple("go", "ogle");
simple* s3 = new simple("stack", "overflow");
simple* s4 = new simple("go", "good");
simple* s5 = new simple("my", "overflow");

在上面的示例中,集合应该只包含 s1、s2、s4 和 s5。

考虑到类的数据成员(即s1和s2),如何在集合中存储唯一的类对象?

我尝试了以下比较器功能,但它不起作用。

struct myCom {
   bool operator()(const simple* a,const simple* b){
      return *a < *b;
   }
};

注意:在我的情况下,排序并不重要,如果插入未排序的元素对我来说没问题。

【问题讨论】:

  • 你为什么使用指针?
  • 有趣的operator&lt;。它甚至没有使用提供的参数。
  • 澄清上述评论:当明显的意图是将thiss进行比较时,代码将thisthis进行比较
  • 一个更复杂的问题是“独特”是什么意思,以及比较的两个部分是如何相互作用的。通常的方法是让第二个充当第一个的决胜局。这在提供的规则中没有完成。混合这两种比较的其他方法可以创建有效的排序,但引用的一种(在修复上述错误之后)不会。
  • 鉴于唯一性的定义,您需要以通常的方式重写比较,以便仅当第一部分相等时才涉及第二部分。 Brahim 引用了您的订购无效的确切规则。但即使它是有效的,它也不是你所需要的。您需要常见的决胜局模式。

标签: c++ stl set operator-overloading


【解决方案1】:

您正在存储指针,因此比较器只是比较内存地址,而不是您的自定义 operator&lt;

停止使用new并将实际对象存储在地图中:

std::set<simple> mySimpleSet;
mySimpleSet.emplace("stack", "overflow");
mySimpleSet.emplace("go", "ogle");
mySimpleSet.emplace("stack", "overflow");
mySimpleSet.emplace("go", "good");
mySimpleSet.emplace("my", "overflow");

或者如果您真的需要存储指针,那么您必须提供一个自定义比较器,该比较器不比较内存地址,而是比较这些内存地址处的对象。

您的operator&lt; 也有缺陷。您正在使用std::string,因此请使用std::string::compare 而不是strcmp,并且您没有使用参数s。这样的事情会更好:

bool operator<(const simple& s) {
  return getS1() < s.getS1() && getS2() < s.getS2();
}

【讨论】:

  • 标准要求比较操作必须是严格的弱排序。我不确定是不是这样。 transitivity of incomparability我觉得不成立
  • 不使用compare(),你可以使用std::stringoperator&lt;
  • @NathanOliver,因为要求仅将第二个字符串用作第一个字符串的决胜局,std::string::operator&lt; 不是进行第一次比较的正确方法。只是看起来它可能是正确的,因为没有先修复另一个错误。
  • 您能否为此添加使用类指针的解决方案?
  • std::tie(s1, s2) &lt; std::tie(s.s1, s.s2)
猜你喜欢
  • 1970-01-01
  • 2015-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-18
  • 2022-07-31
  • 2018-12-12
  • 2010-11-06
相关资源
最近更新 更多