对于operator ==来改变其操作数是不好的做法?

JBe*_*ley 21 c++ comparison equality const operator-overloading

脚本

我有一个课我希望能够比较平等.这个类很大(它包含一个位图图像),我会多次比较它,所以为了提高效率,我要对数据进行哈希处理,只检查哈希是否匹配.此外,我将只比较我的对象的一小部分,所以我只是在第一次完成相等性检查时计算哈希值,然后使用存储的值进行后续调用.

class Foo
{
public:

   Foo(int data) : fooData(data), notHashed(true) {}

private:

   void calculateHash()
   {
      hash = 0; // Replace with hashing algorithm
      notHashed = false;
   }

   int getHash()
   {
      if (notHashed) calculateHash();
      return hash;
   }

   inline friend bool operator==(Foo& lhs, Foo& rhs)
   {
      if (lhs.getHash() == rhs.getHash())
      {
         return (lhs.fooData == rhs.fooData);
      }
      else return false;
   }

   int fooData;
   int hash;
   bool notHashed;
};
Run Code Online (Sandbox Code Playgroud)

背景

根据这个答案的指导,平等运算符的规范形式是:

inline bool operator==(const X& lhs, const X& rhs);

此外,操作符重载以下一般建议给出:

始终坚持运营商众所周知的语义.

问题

  1. 我的函数必须能够改变它的操作数以执行散列,所以我不得不将它们变为非const.是否有任何潜在的负面后果(示例可能是标准库函数或STL容器,它们将operator==具有const操作数)?

  2. 如果operator==突变没有任何可观察到的影响(因为用户无法看到哈希的内容),是否应该将变异函数视为与其众所周知的语义相悖?

  3. 如果上述任何一个的答案都是"是",那么什么是更合适的方法呢?

Dan*_*rey 37

它似乎是一个完全有效的mutable成员用例.您可以(并且应该)仍然operator==通过const引用获取参数,并为类提供mutable哈希值的成员.

然后,您的类将具有哈希值的getter,该哈希值本身被标记为const方法,并且在第一次调用时延迟评估哈希值.这实际上是为什么mutable被添加到语言中的一个很好的例子,因为它没有从用户的角度改变对象,它只是一个实现细节,用于在内部缓存昂贵的操作的价值.

  • 因为没有提到 - 如果你打算使用`mutable`来执行缓存,建议以线程安全的方式这样做,因为否则`operator ==`修改了`Foo `可以通过同时从两个线程调用同一个对象来观察它.即使你从未在你的代码中明确地这样做,[至少是一些C++委员会成员的意见](http://isocpp.org/blog/2012/12/you-dont-know-const-and-mutable -herb-sutter)标准库执行此操作是合法的. (9认同)
  • 请注意,通过使用0作为sentinal散列并执行`if(atomic_load(&hash)!= 0)atomic_store(&hash,calc_hash());可以使线程安全. (5认同)

Che*_*Alf 12

使用mutable的要缓存,但不影响公共接口的数据.

你现在,"变异"→ mutable.

然后从逻辑性的 角度思考const,保证对象为使用代码提供什么.