Table of Contents
- Special Member Functions: Constructors, Destructors, and the Assignment Operator
- Operator Overloading
- Memory Management
- Time and Date Library
- Object-Oriented Programming and Design Principles
- The Standard Template Library (STL) and Generic Programming
- Exception Handling
- Runtime Type Information (RTTI)
- Signal Processing
- Creating Persistent Objects
- Bit Fields
- New Cast Operators
- Environment Variables
- Variadic Functions
- Pointers to Functions
- Function Objects
- Pointers to Members
- Lock Files
- Design Patterns
- Dynamic Linking
- Tips and Techniques
- Five Things You Need to Know About C++11 Unions
- A Tour of C99
- A Tour of C1X
- C++0X: The New Face of Standard C++
- C++0x Concurrency
- The Reflecting Circle
- We Have Mail
- C++ Sudoko, or How to Become a Real Hacker
- Member Name Lookup
- An Operating Overloading Question
- Living Without New
- Solving a Mysterious Compilation Error
- A Magical printf() Call or a Buggy Mess?
- Submitting a Library to the Standards Committee
- The Portable Datatypes Dilemma
- Can I Assign Pointers to a Specific Memory Address?
- Header File Naming Issues
- The Linkage of Enumerations
- unique_ptr And The Deprecation Of auto_ptr
- A const Member Function Conundrum
- A Response to Linus Torvalds' C++ Diatribe
- Pseudo Constructor Initializers
- Comment Terminators and The Keyword int
- Questions About enum Types
- Pointers to volatile
- Warnings on const Declarations
- Questions About inline
- The Costs of Virtual Functions
- More on Rvalue References
- Questions About Virtual Functions and Copy Constructor Calls
- More on Functions and the Safety of Union-Based Cast
- More on Default Initialization
- Overriding new and delete
- Are Constructors the Bane of Real-Time Programming?
- What is Required of a Move Constructor
- What's RAII All About?
- An auto_ptr Conundrum
- Where Has <tt>std::array</tt> Gone?
- Why Comparison Operators Are Declared Friends
- Detecting Memory Leaks to Improve Performance
- What Does Alignment Have to Do with Pointers?
- A Question about Class Member Initializers
- A Static Anonymous Structs Conundrum
- The Soapbox
- Numeric Types and Arithmetic
- Locales and Internationalization
What's RAII All About?
Last updated Jan 1, 2003.
RAII is a widely-used idiom in C++. However, there's some confusion and misconceptions about this idiom so it's time to demystify it.
Is RAII a Synonym for Smart Pointers?
Textbooks and articles say that in order to implement RAII, one needs to have something like auto_ptr, shared_ptr , unique_ptr so that when the objects get destructed, the resource should be de-allocated automatically. What if I have a raw pointer? My code ensures that the pointer is released in case of exception (say in destructor). Likewise, my constructor takes care of initializing that pointer. Does that constitutes RAII or do I need to use one of the standard smart pointer classes mentioned above?
This is a very good question. The C++ literature often implies that RAII is all about smart pointers. It also implies that smart pointers are standard class templates. Both these statements are inaccurate. RAII is an acronym originally introduced in one of the earlier editions of Bjarne Stroutsrup's The C++ Programming Language. It stands for "resource acquisition is initialization"; a phrase whichI find a bit lacking. For starters, it focuses only on one of the two essential components of RAII -- initialization. Secondly, even that part isn't described clearly. First, let's see what RAII is not.
It's not Necessarily About Pointers
RAII is often used for automating memory management and avoiding memory leaks. However, the idiom itself has nothing to do with memory or with pointers. RAII is a very general concept that applies to what you can generally define as transactions. I will get to that in a moment. Suffice it to say that files, threads, database transactions, network data exchange and even getting a scoop of ice-cream from your freeze are all instances of RAII operations, or transactions.
It's not Necessarily about Exceptions
While exception present the biggest challenge for avoiding resource leaks, RAII isn't necessarily confined to programs that use exception handling (directly or indirectly). In fact, most RAII implementations are simply meant to remove the burden of manual resource release from the programmer, regardless of exceptions. RAII is more about automation, less about exceptions.
It's not Necessarily about Standard Classes
You don't have to use a standard class such as auto_ptr, ifstream, string or vector to achieve RAII (yes, all of these classes do implement RAII). You can write your own classes with RAII in mind.
What's in a Transaction?
Now let's see what RAII truly is. Many programming tasks and real-life tasks constitutes of three distinct operations, two of which are essential. I will refer to these tasks as transactions.
Initialization. Before you access a resource, say write data to a file, lick cold ice-cream or take a shower, you need to perform a certain initial operation: open the freezer's door, open the file, allocate memory from somewhere, instantiate a thread object, turn the car-keys in the switch etc.
Usage. The second step consists of using the resource acquired in step 1. That means for example, taking out the ice-cream box outside the freezer (something you can do only after opening the freezer's door), write data to a file that you've just opened, write data to a memory address that you've just allocated, and so on. In some cases, the usage part doesn't exist.
Release. Whether your task includes the usage part or not, a transaction requires an explicit release operation. The release phase usually undoes the effects of the initialization: it closes the freezer's door, releases a memory locks, frees memory allocated from the heap, closes a file (even if you haven't read or written anything), commits or rolls back a database transaction and so on.
RAII packs these essential initialization and release phases into a class' constructor and destructor, respectively. The usage part is often implemented as a distinct member function (write(), execute_thread(), query the database, send a packet of data to a socket, or fill your glass with some scoops of ice-cream). We can conclude that RAII exists in any class whose destructor releases whatever its constructor has acquired.
C++ is one of the few languages that support RAII. Why is this? In order to implement RAII, you need destructors. While every OOP language has constructors, very few of them have proper destructors. Recall that finalizers are not destructors because finalizers are optional and they are non-deterministic. You can't tell when exactly a finalizer will run -- in five seconds, in two years or indeed, never.
Back to the original question, the answer is positive. If you have a class whose constructor allocates memory and whose destructor releases that memory, then you have RAII. Of course, it's more convenient to use a ready-made standard class that already implements this functionality, say unique_ptr. However, if you prefer to use your own classes for automating the handling of transactions, that would make perfect RAII.