The following apparently results in a compilation error in C++23:
int& f(int& x) {
int y = ++x;
return y;
}
error: cannot bind non-const lvalue reference of type 'int&' to an rvalue of type 'int'
But this one doesn't seem to even give us a warning:
int& f(int x) {
int &y = ++x;
return y;
}
Is this so much more difficult to catch during the compilation phase?
Thanks.
To understand the difference, one must understand why the code fails to compile in C++23.
Namely, in the first example, y
is move-eligible because it names an implicitly movable entity and appears in a return
statement. Therefore:
The expression is an xvalue if it is move-eligible (see below); an lvalue if the entity is a function, variable [...]
An implicitly movable entity is a variable of automatic storage duration that is either a non-volatile object or an rvalue reference to a non-volatile object type.
In the first example, the move-eligibility of y
makes it an rvalue, and the returned reference cannot bind to it.
In the second example, y
does not name an implicitly movable entity, so it's considered to be an lvalue, and the reference binding succeeds.
The fact that the first example doesn't compile is not because the C++ committee has made an effort to detect dangling references; instead, this is just a convenient side effect of some wording changes when it comes to implicit moves in return
statements.
Detecting dangling references outside of this one, trivial case is very difficult. It generally requires lifetime annotations for functions, similar to Rust. Some proposals are focused on detecting simple cases at least.
For example, Herb Sutter has proposed standardizing analysis based on acyclic control flow graphs (ACFGs) in P1179: Lifetime safety: Preventing common dangling. This would at least make local analysis (within the same function) possible. The fact that this proposal is 47 pages long demonstrates that it's not a trivial issue though.
More trivial cases can be caught with @BrianBi's proposal P2748: Disallow Binding a Returned Glvalue to a Temporary