Lambda Functions in C++ for RAII

I learned a new trick recently at Microsoft involving the use of C++ lambda functions for automatic resource cleanup, which I thought was pretty cool. It involves combining the RAII programming pattern with a new feature of C++ 0x, namely lambda functions.

What is RAII?

RAII stands for Resource Acquisition Is Initialization, a design pattern which is popular in languages such as C++, D, and Ada. The idea is that you want to acquire resources during the initialization of objects, i.e. as soon as possible, so that you cannot accidentally use an uninitialized object, and also that you want your object to automatically release the resource upon destruction. One of the main advantages of this pattern is that your resources will always be released, even if there are errors or exceptions between when your object is initialized and your object goes out of scope. How does one do this? Here’s a simple example:

#include 
using namespace std;
class FileCloser
{
public:
FileCloser(char* fname)
{
fp = fopen(fname, "r");
}
void ReadLine(char* line, int count)
{
fgets(line, count, fp);
}
~FileCloser()
{
fclose(fp);
}
private:
FileCloser() { }
FILE* fp;
};

int main(int argc, char* argv[])
{
FileCloser fc("test.txt");
char line[100];
fc.ReadLine(line, 100);
cout << line << endl;
return 0;
}

As you can see, we didn’t have to explicitly call fclose on the file pointer because our FileCloser object’s destructor did it for us as soon as the FileCloser object went out of scope in main. Thus, even if we change main to the following, we will still close fp after the exception is thrown:

int main(int argc, char* argv[])
{
FileCloser fc("test.txt");
char line[100];
fc.ReadLine(line, 100);
cout << line << endl;
throw;
return 0;
}

What are lambda functions?

Lambda functions are a new feature of the proposed new standard for the C++ programming language called C++0x, although it’s likely to be introduced sometime in 2009. They are a functional programming technique based on lambda calculus, which you may or may not remember from Theory of Computation. Or was it Programming Languages? Either way, I like to think of it as defining an anonymous inline method where you need it, instead of having to define your own function pointer or delegate method elsewhere. Here’s an example of a simple lambda function:

#include 
#include
#include
using namespace std;
int main(int argc, char* argv[])
{
vector<int> v = { 1, 2, 3, 4, 5 }; // Another new feature of C++ 0x
for_each(v.begin(), v.end(), [](int& x) { x = x * x; });
for_each(v.begin(), v.end(), [](int x) { cout << x << endl; });
return 0;
}

How to use lambda functions to perform RAII

Here’s where we combine these two techniques to perform RAII using lambda functions. In the first code snippet I showed you where we used RAII to automatically release the resource, we still had to define our own class, complete with a destructor, in order to get the kind of resource release we want in the face of errors and exceptions. And although you could design a generic class which could handle automatically deleting pointers which were allocated via new, you would have to create a separate class for each resource type if you have to do something a little bit more complicated to release a resource (for example, by calling a method). But thanks to lambda functions, this is no problem:

#include 
#include
using namespace std;
using namespace std::tr1;

int main(int argc, char* argv[])
{
FILE* fp = fopen("test.txt", "r");
shared_ptr fileReleaser(fp, [](FILE* fp) { fclose(fp); });
char line[100];
fgets(line, 100, fp);
cout << line << endl;
throw;
return 0;
}

The shared_ptr in this example is used to create a sharable pointer to the object we want to release. The arguments to its constructor are first the pointer, and then a pointer to a deleter method, in this case the lambda function. When the shared_ptr goes out of scope outside of main it will automatically call the lambda function to release the file.

Summary

In summary, RAII is a great defensive programming technique you can use to make sure your resources are released and your code doesn’t leak, and lambda functions are a great new way to make using RAII much less painful than it ever was before.

References

Wikipedia: RAII
HackCraft: RAII
Wikipedia: C++0x
Herb Sutter’s Blog
MSDN: shared_ptr

Published by

HexarA

Seattleite. Climber. Snowboarder. Traveler. Party rocker. Technologist. Spanish enthusiast. Fun-seeker.

2 thoughts on “Lambda Functions in C++ for RAII”

  1. So, I don’t see any real advantages over auto_ptr for new/delete RAII. However, this is a nice trick for open/close resources. I’m assuming is would also be well suited from creating an auto releasing mutex.

    Like

  2. This is the pattern that I was looking for, thanks for explaining it.

    In the end I actually implemented something else because in my case I wanted to replace a pattern of `if (!init()) goto error; return true; error: release(); return false;` where the resource is released locally only if init() failed (for a successful init(), the resource is released elsewhere).

    So my implementation was something like this:


    auto releaseOnError = [this]() -> auto { release(); return false; };

    if (!init())
    return releaseOnError();

    if (!anotherStep())
    return releaseOnError();

    return true;

    The release step is actually a bit more complex and I also use it to log the specific error, etc.

    Like

Leave a comment