ARTICLE AD BOX
Is this so much more difficult to catch during the compilation phase?
The important thing to understand here is that C++ does not have a rule like "you shall not have a dangling reference" for the compiler to enforce. Instead, there are a bunch of more specific language rules that, when added up, catch some instances that would lead to dangling.
Specifically, in this example:
int& f(int& x) { int y = ++x; return y; }We now have a rule that says that return y; should treat y as an rvalue because it's a local variable (see Jan Schultke's answer for the specific rule and terminology), and you can't bind an rvalue to int&, so this doesn't compile. That's great, because had it compiled (like it used to), that would be a dangling reference.
However, in this example:
int& f(int x) { int &y = ++x; return y; }There just isn't a simple(~ish) rule to reject this function. y is already a reference, so returning it is fine. Binding the result of ++x to a reference is also fine. This is only wrong for a more complicated lifetime analysis - that ++x is an lvalue with the same lifetime of x, so returning y would exceed the lifetime of x. But there's no specific C++ rule here. You'd need to run a static analyzer to catch This.
Which, clang-analyzer does (but not clang or gcc with any warning that I can find):
<source>:3:5: warning: Address of stack memory associated with local variable 'x' returned to caller [clang-analyzer-core.StackAddressEscape] 1 | int& f(int x) { | ~~~~~ 2 | int &y = ++x; 3 | return y; | ^ ~ <source>:3:5: note: Address of stack memory associated with local variable 'x' returned to caller 1 | int& f(int x) { | ~~~~~ 2 | int &y = ++x; 3 | return y; | ^ ~Similarly there was experimental work on more lifetime tracking (-Wlifetime) that caught this, although the warning you got was "returning a dangling pointer" which is maybe not the best text.
Otherwise - C++ isn't Rust in this sense. There just isn't such a "you shall not dangle" rule (which makes even more complicated examples involving containers and views and iterators much harder to properly diagnose). But given that we have an easy rule which rejects one dangling reference but no such easy rule for the other, I guess this is an existence proof that indeed one is much more difficult to catch than the other.
