Definition of Equality
Asked Answered
K

3

5

When overloading the "==" operator in c++, is there a standard definition as to what equality explicitly means, or a set of guidelines as how "==" should behave?

I currently have a class that does not store its entire self in memory. It basically uses a priority queue to determine how often an object inside itself is being used and when objects are popped from the end of the queue they are removed from memory and written to disk.

So now the problem occurs with equality, what does it mean for two of these objects to be equal. Because we could start with objects A and B which are the same in every way, they have loaded the same data into memory and they have the same data on disk. But then after calling a series of functions on A and B they could now be different. A and B still have the same data on disk but they they have different data loaded into memory. So the question is should A == B resolve to true or false?

Are there a set of rules or guidelines that define how this should work? Or is this just a situation where I decide what makes the most sense for the program and document what "==" does?

Krisha answered 20/12, 2012 at 22:34 Comment(2)
It depends on your data structure, its semantics, and its invariants. There is no one-size-fits-all answer.Anticlimax
If the meaning you want it to have is not intuitively clear, you are better off implementing a member function with an appropriate name and not overload ==.Michalmichalak
F
11

There's no definition in the standard on how an overloaded operator == should behave.

But a good enough guideline is this - if you have to think about it for as long as you have, you probably shouldn't even be overloading operator ==. If it's not intuitive, it does more harm than good.

So the question is should A == B resolve to true or false?

IMO, it should result in a compiler error. :)

Fannie answered 20/12, 2012 at 22:36 Comment(9)
I agree. Operator overloading is only good when the meaning of the overloads is extremely intuitive. The only places I think it's useful are numerical types, smart pointers, and operator[] on containers. Use something like containsSameData().Urogenital
Thanks, now that you say it makes a lot more sense to have two different member functions that test the different types of equality I mentioned, that way I'm not limiting the user.Krisha
@larsmans: Luchian said "if you have to think about it for as long as you have..." I doubt he'd think that long about it for containers or numeric types.Zamarripa
@larsmans I'm not saying C++ is perfect. Smart pointers have overloaded operator ==? What does it do? I honestly don't know. Does it compare the inner pointers? The objects they point to? IMO, that's not a very good example...Fannie
@larsmans: I think if you have to think a long time about what operator== should do, then it isn't intuitive, and should therefore be designed so that any attempt to use operator== results in a compiler error. I agree with what Luchian said 100%. (Or, I did until he mentioned smart pointer ==. That makes sense to me. They're equal if they point to the same object.)Zamarripa
@MooingDuck that doesn't count, it's a comment :P.Fannie
@larsmans my class does not overload the < operator. The class uses a priority queue but is not contained within one.Krisha
Undid the -1 (after a trivial edit, hope @LuchianGrigore doesn't mind). Sorry about that.Mabe
@larsmans no need, I see your point. I do stick to mine though :)Fannie
M
16

Any operator== overload should respect the axioms of an equivalence relation, that is

  • x == x, for all objects x
  • if x == y, then y == x
  • if x == y and y == z, then x == z.

Many algorithms using == rely on it implementing an equivalence relation, formalized in §17.6.3.1 as the EqualityComparable concept.

Mabe answered 20/12, 2012 at 22:37 Comment(3)
the Container Requirements 23.2.5 for unordered associative containers do require that a key equality predicate (which defaults to std::equal_to, i.e. operator==) induces an equivalence relation.Murat
@rhalbersma Thanks, I guess I missed that bit.Mabe
Just rechecked the Standard: table 17 in 17.6.3.1 describes Template argument requirements and defines the concept EqualityComparable in terms of an equivalence relations using your 3 conditions. The EqualityComparable concept applies to all containers as a whole, to their allocators, to all iterators, and to predicates for algorithms such as unique and the unordered containers. So basically users can do whatever they want with an operator== but if they want to correctly interact with the Standard Library, they better conform to the equivalence relation defined by EqualityComparable.Murat
F
11

There's no definition in the standard on how an overloaded operator == should behave.

But a good enough guideline is this - if you have to think about it for as long as you have, you probably shouldn't even be overloading operator ==. If it's not intuitive, it does more harm than good.

So the question is should A == B resolve to true or false?

IMO, it should result in a compiler error. :)

Fannie answered 20/12, 2012 at 22:36 Comment(9)
I agree. Operator overloading is only good when the meaning of the overloads is extremely intuitive. The only places I think it's useful are numerical types, smart pointers, and operator[] on containers. Use something like containsSameData().Urogenital
Thanks, now that you say it makes a lot more sense to have two different member functions that test the different types of equality I mentioned, that way I'm not limiting the user.Krisha
@larsmans: Luchian said "if you have to think about it for as long as you have..." I doubt he'd think that long about it for containers or numeric types.Zamarripa
@larsmans I'm not saying C++ is perfect. Smart pointers have overloaded operator ==? What does it do? I honestly don't know. Does it compare the inner pointers? The objects they point to? IMO, that's not a very good example...Fannie
@larsmans: I think if you have to think a long time about what operator== should do, then it isn't intuitive, and should therefore be designed so that any attempt to use operator== results in a compiler error. I agree with what Luchian said 100%. (Or, I did until he mentioned smart pointer ==. That makes sense to me. They're equal if they point to the same object.)Zamarripa
@MooingDuck that doesn't count, it's a comment :P.Fannie
@larsmans my class does not overload the < operator. The class uses a priority queue but is not contained within one.Krisha
Undid the -1 (after a trivial edit, hope @LuchianGrigore doesn't mind). Sorry about that.Mabe
@larsmans no need, I see your point. I do stick to mine though :)Fannie
A
2

ALL operator overloading should do "what you expect". There is no point in having an operator == that returns true if the objects aren't substantially the same. How you define "the same" is of course potentially something we could argue about. One could implement a "nocasestring" where it behaves like a string, but if you have a string "HELLO" and one "hello", they are considered equal, because case doesn't matter. Or if you implemented your own "Float" class, where == does some math to avoid the fragile comparison of regular floating point. So yes, there are cases where == doesn't do EXACTLY "for all elements is a. == b.", but it should really be the exception.

Likewise, if an operator doesn't make totally sense, don't make it do something "surprising" (e.g. - for strings - what does it do? Or multiply one string by another string - multiply by integer may have a meaning).

Surprises in programming is a bad idea. If things don't work the way you EXPECT, you get bad experiences from reading/modifying the code.

Afghani answered 20/12, 2012 at 22:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.