Resource allocation is initialization or RAII for short may be hard to pronounce but will help you write better and simpler code.
Listen to this episode for an example that should help explain why RAII is an important technique to help us simplify our code so that we don’t have to manually clean up resources when we’re done. You can also read the full transcript below.
There’s usually some tradeoff you need to consider when programming. Not everything has a single best way to do something and usually that means you have choices. Each choice will help you in some way and cause problems in another.
One of the best known choices is between good, fast, and cheap. Pick any two.
• If you want something made well that’ll last and you want it quick, then it won’t be cheap.
• If you don’t want to sacrifice the quality and have a limited budget, then you’ll have to wait because you won’t get it soon.
• Or if you want something as soon as possible and don’t want to spend a lot of money, then you should expect problems with the quality.
There’s a tradeoff with RAII just like anything else. But the problems it helps you solve are well worth the extra code needed. And most of the time, you don’t have to write this extra code. You just need to be aware of the situation and know how to use RAII to your advantage.
In order to make full use of RAII, you’ll need a language like C++. I say like C++ even though C++ is the only language I know about that makes full use of RAII. But since there are hundreds of programming languages, it’s possible that you can use this technique in other places.
Languages with garbage collection are not going to use RAII to its full extent. That’s because you really need a language that defines the lifetime of objects and especially the exact moment that their destructors will be called in order to make full use of RAII. Listen to episodes 17 through 22 for more information about object-oriented programming, constructors, and destructors.
Imagine this scenario. You’re about to leave your house to go to work but want to fix something to eat first. So you crack open an egg into a frying pan and set it on the stove to cook. Then to save time, you start getting ready for work. The phone rings and you answer it. Just a robot sales call. But it distracts you just enough that you forget all about your egg, finish getting ready for work and leave to catch the 9am bus.
You have a nagging feeling that you’re forgetting something but can’t quite remember what. You remember the egg only when you get home and open the door and smoke pours out. The whole house smells really bad. There was no fire but it’s hard to breath until you get all the windows open to vent out the smoke and smell. Your frying pan is warped and there’s nothing recognizable about the egg anymore.
All of this happened because you forgot to turn off the stove. Maybe it was also caused by the phone call. But it comes down to this. Anytime we have to remember to do something important either in real life or in programming, we can expect mistakes like this to happen.
What if there was a new type of stove that would shut itself off when it detected that nobody remembered it was on? Maybe it could detect if nobody was inside the house and turn off on its own? In order for this to work properly, the stove would need to turn itself off right away. It wouldn’t help much if you forgot to turn off the stove, the stove also recognized that nobody was home, but then it waited for a few extra hours before finally deciding that it should react. It needs to react right away in order to prevent burning.
And this is where garbage collected languages struggle. There’s no fixed time when you can rely on your resources being cleaned up. It might happen right away, or it might happen hours later.
The C++ language is very precise about when objects get destroyed and in what order. And you can count on the destructors being called even if an exception is thrown and your program stops everything to handle the exception. While looking for the code to handle the exception, the C++ language gives you the guarantee that destructors will be called.
What this means is that you can have a Stove object in your code that gets created inside a method called makeBreakfast. The moment the makeBreakfast method completes or leaves due to an exception, it will destroy the Stove object. The Stove object will then turn itself off inside its destructor.
Some people say that C++ is difficult because you have to manage memory yourself and have to remember to free the memory when you’re done with it. They say that C# or Java or Python is better because you don’t have to worry anymore. The garbage collector will handle everything for you. Well, the problem is that you don’t know when this will happen.
Because C++ gives you guarantees that object destructors will be called, you can use them to manage your memory and other resources too.
Anytime you allocate a resource, what you need to do is immediately use that to initialize an object. This new object will do whatever you need it to do when it gets destructed. Guaranteed. You don’t need to remember anymore. This is where RAII gets its name. Resource allocation is initialization. This means that you should think of protecting anything you allocate or that needs some special handling when you’re done with it by passing it to some other object which will do this work for you the moment the protecting object gets destroyed.
Let’s go back to the Stove object for a moment. It will already do the right thing and turn itself off whenever it gets destroyed. And if you create a Stove object as a local variable inside a function, then it will do the right thing the moment the function is done.
But you don’t always want to create local stack-based objects like this. Sometimes, you want to allocate some memory and construct the Stove in that memory. You’ll get a pointer to the new Stove object. Everything will work just fine except that the pointer will not cause the Stove to be destroyed unless you tell it to. This is why some people say that C++ is hard because you always need to remember to destroy the objects that your pointers point to.
The solution is to stop using a raw pointer. Use an RAII object such as a smart pointer instead. Now when you create a new Stove object in your computer’s memory, you use the pointer to initialize a smart pointer object. The smart pointer behaves just like the raw pointer except that it has a little extra code that will automatically delete your Stove object when you’re done with it. This will cause the Stove to turn off the flame and you can come home to a smoke-free house.
Using RAII doesn’t add much if any extra work on your part. You just need to be aware that you should use it. It’s an engineering tradeoff that’s well worth the price.