使用operator!=运算符<是否安全?在std :: set中?

时间:2012-10-08 12:56:40

标签: c++ algorithm set

我有一个带有一些成员的结构,我有一个实现的运算符==。实施运营商是否安全<在operator ==的帮助下?我想在一个集合中使用这个结构,我想检查这个结构是否是唯一的。

struct Data
{
  std::string str1;
  std::string str2;
  std::string str3;
  std::string str4;

  bool operator==(const Data& rhs)
  {
    if (str1 == rhs.str1
     && str2 == rhs.str2
     && str3 == rhs.str3
     && str4 == rhs.str4
       )
      return true;
    else
      return false;
  }

  // Is this ok??
  bool operator<(const Data& rhs)
  {
    return !this->operator==(rhs);
  }
}

所以当我将这个结构插入到std :: set时会发生什么?

4 个答案:

答案 0 :(得分:9)

不,这很不安全。实现它的最简单方法是通过std::tie

#include <tuple>
struct Data
{
  std::string str1;
  std::string str2;
  std::string str3;
  std::string str4;

  bool operator<(const Data& rhs) const // you forgot a const
  {
      return 
      std::tie(str1, str2, str3, str4) < 
      std::tie(rhs.str1, rhs.str2, rhs.str3, rhs.str4);
  }
}

答案 1 :(得分:6)

不,那不安全。您定义<a < bb < a的方式同时适用。

  

所以当我将这个结构插入到std :: set时会发生什么?

行为未定义,因此任何内容都是允许的,并且在不同的实现中可能会有所不同。

答案 2 :(得分:3)

您的代码建议如果A!=B,那意味着A<B肯定是错误的,因为它也可能是A>B

您必须以与>相同的方式实施<operator==运算符,这意味着通过成员比较对象。您可以根据自己的成员决定如何确定A是否比B“更多”或“更少”。

如果您在任何标准库容器中使用该运算符,您将获得UB。

答案 3 :(得分:2)

您需要以自己的方式定义operator<。您无法在operator<方面实施operator==,但您可以采取相反的措施。

考虑这个真值表中的悖论:

"a" < "b" : TRUE
"b" < "a" : TRUE

如果你的operator<的实现产生了上述悖论,如果你用operator==来实现它,那么你没有正确实现严格的弱排序。你实施的是乱七八糟的混乱。

您需要确定哪些成员字符串优先于其他成员字符串,然后按顺序执行它们之间的比较 - 从最重要到最不重要。

例如,如果字符串的优先级从最重要到最不重要:

  1. str1
  2. str2
  3. str3
  4. str4
  5. ...然后这会产生operator<的以下算法:

    bool operator<(const Data& rhs) const
    {
      if( str1 < rhs.str1 )
        return true;
      if( rhs.str1 < str1 )
        return false;
      if( str2 < rhs.str2 )
        return true;
      if( rhs.str2 < str2 )
        return false;
      if( str3 < rhs.str3 )
        return true;
      if( rhs.str3 < str3 )
        return false;
      if( str4 < rhs.str4 )
        return true;
      if( rhs.str4 < str4 )
        return false;
    
      return false;
    }
    

    使用此功能,您可以选择根据operator==重新实施operator<。然而,您可以假设时间复杂性固有的低效率:

    bool operator==(const Data& rhs) const
    {
      return !operator<(rhs) && !rhs.operator<(*this);
    }