"Rust basically just calls 'free' for you the moment something goes out of scope."
C++ does that too with RAII. Go ahead and use whatever STL containers you like, emplace objects onto them, and everything will be safely single-owned with you never having to manually new or delete any of it.
The difference is that C++'s guarantees in this regard derive from a) a bunch of implementation magic that exists to hide the fact that those supposedly stack-allocated containers are in fact allocating heap objects behind your back, and b) you cooperating with the restrictions given in the API docs, agreeing not to hold pointers to the member objects or do weird things with casting. You can use scoped_ptr/unique_ptr but the whole time you'll be painfully aware of how it's been bolted onto the language later and whenever you want you can call get() on it for the "raw" underlying pointer and use it to shoot yourself in the foot.
Rust formalizes this protection and puts it into the compiler so that you're prevented from doing it "wrong".
> a bunch of implementation magic that exists to hide the fact that those supposedly stack-allocated containers are in fact allocating heap objects behind your back
The heap is but one source for allocator-backed memory. I've used pieces of stack for this, too. One could also use an entirely staticly sized and allocated array.
the tradeoff is that ~you have to guess where rust is doing the frees, and you might be wrong. in the end this would be strictly equivalent to an explicit instruction to free, with the compiler refusing to compile if the free location broke the rules.
If you're in hard realtime land then you can't have any allocations at all; that's a pretty different ballgame.
Destructors should be as simple and side-effect free as possible, with the exception of things like locks or file handles where the expectation is very clear that the object going out of scope will trigger a release action.
C++ does that too with RAII. Go ahead and use whatever STL containers you like, emplace objects onto them, and everything will be safely single-owned with you never having to manually new or delete any of it.
The difference is that C++'s guarantees in this regard derive from a) a bunch of implementation magic that exists to hide the fact that those supposedly stack-allocated containers are in fact allocating heap objects behind your back, and b) you cooperating with the restrictions given in the API docs, agreeing not to hold pointers to the member objects or do weird things with casting. You can use scoped_ptr/unique_ptr but the whole time you'll be painfully aware of how it's been bolted onto the language later and whenever you want you can call get() on it for the "raw" underlying pointer and use it to shoot yourself in the foot.
Rust formalizes this protection and puts it into the compiler so that you're prevented from doing it "wrong".