>code that has a lot of tricky mathematical algorithms in it, rather than just "plumbing" data between different sources
Your hierarchy is backwards. Borrowing for algorithmic code is easy, it's for writing libraries that can be used by others where it's hard. Rust lets you - makes you - encode in in the API in a way C++ can't yet express.
> I just very rarely have problems with memory errors in C++ code bases with a little thought applied to lifetimes and use of smart pointers
If these are sparing you C++ bugs but causing you to struggle with the borrow checker, it's because you're writing code that depends on constraints that you can't force other contributors (or future you) to stick to. For example, objects are thread-unsafe by default. You can use expensive locks, or you can pray that nobody uses it wrong, but you can't design it so it can only be used correctly and efficiently.
Your hierarchy is backwards. Borrowing for algorithmic code is easy, it's for writing libraries that can be used by others where it's hard. Rust lets you - makes you - encode in in the API in a way C++ can't yet express.
> I just very rarely have problems with memory errors in C++ code bases with a little thought applied to lifetimes and use of smart pointers
If these are sparing you C++ bugs but causing you to struggle with the borrow checker, it's because you're writing code that depends on constraints that you can't force other contributors (or future you) to stick to. For example, objects are thread-unsafe by default. You can use expensive locks, or you can pray that nobody uses it wrong, but you can't design it so it can only be used correctly and efficiently.