Show Lecture.RAII as a slide show.
CS253 RAII
Worst Acronym Ever
RAII means:
- Resource
- Acquisition
- Is
- Initialization
Very Slightly Better
CADRE means:
- Constructor
- Acquires
- Destructor
- Releases
Definition
- RAII means: acquire the resource when you create the variable,
and let the dtor release the resource.
- If you catch yourself thinking “must remember to clean this up”,
then you should be using RAII.
- The object remembers to do the cleanup.
Non-RAII code
Here’s some non-RAII code:
// Acquire resources
FILE *host = fopen("/etc/hostname", "r");
float *scores = new float[253];
char *name = new char[50];
// Use resources
cout << "hi there\n";
// Clean up after ourselves
delete[] name;
delete[] scores;
fclose(host);
hi there
RAII code
The equivalent RAII code:
// Acquire resources
ifstream host("/etc/hostname");
unique_ptr<float[]> scores(new float[253]);
string name(50, 'X');
// Use resources
cout << "hi there\n";
// Clean up after ourselves
hi there
Even better
Sure, unique_ptr does the job. This works fine:
unique_ptr<float[]> scores(new float[253]);
scores[5] = 70;
cout << scores[5];
70
However, vector works just as well, and reads a lot better:
vector<float> scores(253);
scores[5] = 70;
cout << scores[5];
70
So does array (for compile-time sizes):
array<float,253> scores;
scores[5] = 70;
cout << scores[5];
70
As does a plain old C array (for compile-time sizes):
float scores[253];
scores[5] = 70;
cout << scores[5];
70
Why RAII?
It’s not too difficult to remember to free our
resources, but what if something gets in the way?
float *scores = new float[253];
if (getuid() != 0) {
cerr << "Must be super-user!\n";
return 1; // Forgot to delete scores!
}
cout << "hello\n";
delete[] scores;
Must be super-user!
Sure, we could add delete[] scores
to the if clause,
but what if there are several early returns, and many variables?
It’s not very DRY. Also, what about exceptions?
Why RAII?
unique_ptr<float[]> scores(new float[253]);
if (getuid() != 0) {
cerr << "Must be super-user!\n";
return 1;
}
cout << "hello\n";
Must be super-user!
This code isn’t bothered by early returns or exceptions. They will both
cause the unique_ptr to be destroyed, and its dtor will free the
memory.
Simplicity of Description
Consider this non-RAII code:
double *p;
// … region 1 …
p = new double[100];
// … region 2 …
delete[] p;
// … region 3 …
Describe p
in the various regions.
- uninitialized, indeterminate
- pointing to 100 doubles
- indeterminate; probably a stale pointer to the ex-doubles
Simplicity of Description
Consider this RAII code:
unique_ptr<double[]> p(new double[100]);
// … region 1 …
Describe p
in the various regions.
- pointing to 100 doubles
Gosh, that seems easier to understand.
Other Uses
Use RAII when you think “Don’t forget to …”, which might apply to:
- dynamic memory
- files
- mutex
- network sockets
- opening a database
Real-Life RAII
- I treat my teaching assistants as a form of real-life RAII.
- When I need a quiz graded, I don’t give them step-by-step
instructions:
- First, take the quizzes to your office.
- Second, grade the quizzes.
- Third, enter the grades.
- Fourth, return the quizzes so I can given them back to the students.
- No! I say “Here are the quizzes. Do it!” and it gets done, no matter
how often the TA gets interrupted by their life.
- A TA knows how to grade & return quizzes.
- A vector knows how to allocate & free memory.
Real-Life RAII