To me, the borrow checker just feels like an additional type layer I have to reason and think about. In that sense, my thinking when reasoning about lifetimes in Rust is a lot more along the same lines I do in Haskell than something I would be doing in C++ (which I refuse to code in, I'm not capable of writing secure C/++ code.)
The question is what happens when programs don't fit those patterns. Inevitably in any large real world application, there are some objects with lifetimes that need to be managed carefully and don't match conveniently with some sort of scope in a program.
With C++, this is where one would use std::shared_ptr, or something else. In rust, there's Rc. But either way, you've now stepped into a territory where object lifetimes and bugs can be messy.
I find that in most cases where ownership patterns don't fit the Rust model, you can abstract the problematic parts into some kind of collection type and hide them in its own crate --- or better still, find an existing crate that does what you need.
The only remotely common case that still doesn't get handled well, in my experience, is the self-referential struct pattern --- when a value needs to contain references to other parts of the same value.
There's a basic reason for that, namely you can't memcpy a self-referential structure while keeping desired semantics. Rust now has a Pin<> feature to mark data that should not be moved in memory, but its use is still unintuitive and IIRC requires unsafe. In many cases one should perhaps avoid references to self-addresses entirely; often they can be replaced by indexes and/or offsets.
You actually can! For instance, consider a struct with two fields: a Vec<T>, and a &T which references one of the elements of the Vec. Moving the struct (which does the memcpy) does not reallocate the Vec, so the reference in the &T would still be valid. But as far as I know there's no way to represent that in safe Rust; the &T in the struct requires a lifetime, and there's no way to represent "the lifetime of the other field" or even "the lifetime of the struct itself" (something like &'self T).
Yeah, you can use an index in my example (replacing the &T by an usize, and looking up on the Vec every time), but it's not a perfect replacement. A reference would always be valid (and always pointing to the same element), while an index can become invalid if the Vec is truncated, or point to a wrong element if an element is inserted or removed before it in the Vec.
It is a low-level programming language after all. Not being explicit about memory would be a bad thing (it almost always is).
It is just that it is typically more useful/powerful in languages that lack a GC (doesn't necessarily need to be that way though, but my impression).
Why are you crediting C++ for an idea that is probably much older than it?
I think the influence of C++ is much more than just the syntax.