Is the following code well-defined in C++20, or does it have undefined behavior, based on sequencing operation?
#include <iostream>
#include <memory>
using namespace std;
struct A {
A(int i) : a_(i) {}
int Foo(unique_ptr<A>) { return a_; }
int a_ = 0;
};
int main() {
auto a_ptr = make_unique<A>(10);
cout << a_ptr->Foo(std::move(a_ptr)) << '\n';
}
With C++17, this paper proposed stricter expression evaluation ordering.
a->b
ordering (a
before b
) is part of that.
Does this imply that in this case a_ptr->Foo(std::move(a_ptr))
should be sequenced as follows:
A* a_ptr_raw = a_ptr.operator->();
a_ptr_raw->Foo(std::move(a_ptr));
which will make this well-defined.
Yes, it is well-defined... but not intuitive.
It seems that the authors of the paper you quote wanted to make some examples work correctly (i.e. make them do what people expect intuitively), such as this one:
std::string s = “but I have heard it works even if you don’t believe in it”;
s.replace(0, 4, “”).replace(s.find(“even”), 4, “only”).replace(s.find(“ don’t”), 6, “”);
assert(s == “I have heard it works only if you believe in it”); // OK.
In the process, it makes some confusing statements "well-defined", but that does not make them less confusing. Your example is reminiscent of the infamous:
*x = *x++ + 1;