Resources and resource leaks

This tip discusses one method of eliminating resource leaks.

This Content Component encountered an error

Resources and resource leaks
Bjarne Stroustrup

We have all been plagued by memory leaks, but it's even more galling than normal when the memory leak comes in a program that we are writing. This tip, a portion of an article on InformIT, titled Programming with Exceptions, discusses one method of eliminating resource leaks.

Bjarne Stroustrup is the author of C++ Programming Language, the Special Edition.


Consider a traditional piece of code:

void use_file(const char* fn)
{
        FILE* f = fopen(fn,"r");
        // use f
        fclose(f);
}

This code looks plausible. However, if something goes wrong after the call of fopen() and before the call of fclose(), it's possible to exit use_file() without calling fclose(). In particular, an exception might be thrown in the use f code, or in a function called from there. Even an ordinary return could bypass fclose(f), but that's more likely to be noticed by a programmer or by testing.

A typical first attempt to make use_file() fault-tolerant looks like this:

void use_file(const char* fn)
{
        FILE* f = fopen(fn,"r");
        try {
                // use f
        }
        catch (...) {
                fclose(f);
                throw;
        }
        fclose(f);
}

The code using the file is enclosed in a try block that catches every exception, closes the file, and re-throws the exception.

The problem with this solution is that it's ad hoc, verbose, tedious, and potentially expensive. Another problem is that the programmer has to remember to apply this solution everywhere a file is opened, and must get it right every time. Such ad hoc solutions are inherently error-prone. Fortunately, there is a more elegant solution.

It's a fundamental rule that when a variable goes out of scope its destructor is called. This is true even if the scope is exited by an exception. Therefore, if we can get a destructor for a local variable to close the file, we have a solution. For example, we can define a class File_ptr that acts like a FILE*:

class File_ptr {
        FILE* p;
public:
        File_ptr(const char* n, const char* a) { p = fopen(n,a); }
        // suitable copy operations
        ~File_ptr() { if (p) fclose(p); }

        operator FILE*() { return p; }   // extract pointer for use
};

Given that, our function shrinks to this minimum:

void use_file(const char* fn)
{
        File_ptr f(fn,"r");
        // use f
}

The destructor will be called independently of whether the function is exited normally or exited because an exception is thrown. That is, the exception-handling mechanism enables us to remove the error-handling code from the main algorithm. The resulting code is simpler and less error-prone than its traditional counterpart.

The file example is a fairly ordinary resource leak problem. A resource is anything that our code acquires from somewhere and needs to give back. A resource that is not properly "given back" (released) is said to be leaked. Other examples of common resources are memory, sockets, and thread handles. Resource management is the heart of many programs. Typically, we want to make sure than every resource is properly released, whether we use exceptions or not.

You could say that I have merely shifted the complexity away from the use_file() function into the File_ptr class. That's true, but I need only write the File_ptr once for a program, and I often open files more frequently than that. In general, to use this technique we need one small "resource handle class'' for each kind of resource in a system. Some libraries provide such classes for the resources they offer, so the application programmer is saved that task.

The C++ standard library provides auto_ptr for holding individual objects. It also provides containers, notably vector and string, for managing sequences of objects.

The technique of having a constructor acquire a resource and a destructor release it is usually called resource acquisition is initialization.


You can read this entire article at InformIT. You have to register there to see the article, but registration is free.


This was first published in November 2001

Dig deeper on Windows Operating System Management

Pro+

Features

Enjoy the benefits of Pro+ membership, learn more and join.

0 comments

Oldest 

Forgot Password?

No problem! Submit your e-mail address below. We'll send you an email containing your password.

Your password has been sent to:

-ADS BY GOOGLE

SearchServerVirtualization

SearchCloudComputing

SearchExchange

SearchSQLServer

SearchWinIT

SearchEnterpriseDesktop

SearchVirtualDesktop

Close