In which cases does std::optional operator == cause undefined behavior?
Asked Answered
M

1

5

Cppreference has the following description of mixed (optional and some other non-optional type) comparison operators for std::optional:

Compares opt with a value. The values are compared (using the corresponding operator of T) only if opt contains a value. Otherwise, opt is considered less than value. If the corresponding two-way comparison expression between *opt and value is not well-formed, or if its result is not convertible to bool, the behavior is undefined.

What confuses me here is:

  • What would be examples of these not well-formed comparisons?

  • Why don't compilers/STL just reject the invalid comparisons instead of giving us UB?

Mariann answered 23/6, 2020 at 12:46 Comment(2)
Just a guess: T having a strange T::operator==Tham
Or not having operator== at all? Not sure why it's UB rather than ill-formed...Eos
F
9

This stems from imprecise specification, which has since been rectified.

In C++17, these comparisons were specified as:

Requires: The expression *x == *y shall be well-formed and its result shall be convertible to bool.

Requires was a precondition, so failing to meet these conditions would be undefined behavior. But there are many different kinds of "preconditions" - does it mean check this statically, does this mean remove the operator from the overload set if the conditions aren't met, does it mean actual undefined behavior?

In C++20, these are instead specified as:

Mandates: The expression *x == *y is well-formed and its result is convertible to bool.

Which means that the program is ill-formed if the conditions aren't met. Basically, a mandate is a static_assert (or equivalent).

So yes, the standard library is obligated to reject types whose comparison either doesn't exist or doesn't give you something like a bool. This was never actually going to give you undefined behavior (what would an implementation do if it didn't have such an operator, read a bit from /dev/random?) but now it's just much more clearly specified.


These changes came from a series of papers by Marshall Clow entitled "Mandating the Standard Library", this one specifically from P1460 (thanks, Marshall!). The new terminology for specifying the standard library comes from Walter Brown's "Guidelines for Formulating Library Semantics Specifications" paper (P1369).

Fredenburg answered 23/6, 2020 at 13:24 Comment(3)
upvoted, but I am not sure why you are quoting specification that dereferences both x and y, I would presume in cases I ask about only one side is dereferenced. I presume this limitation was also for comparison of optional<T> and optional<U> so the answer still has the same conclusion.Mariann
@Mariann Because all the comparisons are worded the same so I just picked the first one.Fredenburg
"what would an implementation do if it didn't have such an operator?" Return FileNotFound, of course.Banka

© 2022 - 2025 — McMap. All rights reserved.