Scenario
I have a class which I want to be able to compare for equality. The class is large (it contains a bitmap image) and I will be comparing it multiple times, so for efficiency I'm hashing the data and only doing a full equality check if the hashes match. Furthermore, I will only be comparing a small subset of my objects, so I'm only calculating the hash the first time an equality check is done, then using the stored value for subsequent calls.
Example
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;
};
Background
According to the guidance on this answer, the canonical form of the equality operator is:
inline bool operator==(const X& lhs, const X& rhs);
Furthermore, the following general advice for operator overloading is given:
Always stick to the operator’s well-known semantics.
Questions
My function must be able to mutate it's operands in order to perform the hashing, so I have had to make them non-
const
. Are there any potential negative consequences of this (examples might be standard library functions or STL containers which will expectoperator==
to haveconst
operands)?Should a mutating
operator==
function be considered contrary to its well-known semantics, if the mutation doesn't have any observable effects (because there's no way for the user to see the contents of the hash)?If the answer to either of the above is "yes", then what would be a more appropriate approach?