Freeing
You don’t need this section to understand how to use strings correctly. But it does help you understand why ownership is so important in Rust, and why Rust is such an awesome language.
Above, I very briefly mentioned to you the concept of freeing memory. When you allocate memory on the heap, what you’re doing is asking the dynamic memory allocator to set aside a bit of the computer’s memory for you to use. While you’re using that memory, nothing else can use it. The dynamic allocator marks it as off-limits, and will neither give it to your program to use, nor to any other program to use. That’s a good thing; it would be terrible if we asked for a piece of memory, started using it, and then some other function or program wrote over that data with something else entirely!
However, there’s a problem with this. If we keep asking for more memory, we’ll eventually run out. Our computers have lots of memory available, somewhere in the ballpark of 8 billion bytes. But if the programs on your computer never bother to free their memory, this will get used up very quickly. Freeing is a mechanism where you tell the dynamic allocation, “Hey, I’m all done with this memory, you can let something else use it now.”
Many programs in the world written in languages like C and C++ have bugs where they don’t free memory. This can happen for various uninteresting reasons. The impact of this is that your computer runs out of memory, starts running more slowly as the computer tries to find workarounds for the unavailable memory, and eventually, things just start breaking. That’s not good.
But there’s something even worse. Let’s say you do free some memory, and tell the dynamic allocator it can reuse it. But then, by mistake, you keep using that memory. Now your code, and something else, will both be accessing the same bit of memory. If you’re lucky, the operating system may detect that two different programs are trying to use the same bit of memory and just kill your program. Yes, the best-case scenario here is that your program crashes.
In the worst case, you may end up with a major security bug. One function in your program may write some secure data, like a password, into a bit of memory. And another function will think that that piece of memory is holding onto something that’s not security-sensitive, like a username, and send it to another machine. There have been many bugs like this in the history of computers.
Rust is automatically protecting you from all of these bugs. Ownership ensures that there’s always one thing in your program that is responsible for a value. If there’s a dynamic allocation, like with a String
, that one thing is responsible for freeing the memory, and will do so for you automatically. You can’t use the value after it’s been dropped based on the move rules, and you can’t keep a reference to a dropped value based on the borrowing rules.
You may get frustrated at some points in your Rust career with ownership and borrowing rules, but the alternative is far, far worse.