multipart-mixed

Mini-Pattern: Resource User

Next pattern: a great gem buried in the Stroustrup book.

Define a lightweight class for a resource in use, and declare it on the stack. The destructor closes the resource when the instance goes out of scope. This ensures that the resource is always released when no longer needed.

Applicability

Any non-trivial use of resources which must be explicitly released in a C++ application.

Motivation

In C++ there may be several places where you can exit a block of code, including both explicit "return" statements and also exceptions. It can become tedious and error-prone to make sure that a resource (e.g. an open file) is released before exiting a block of code. For example:

void foo()
{
    FILE* file = fopen("/tmp/log", "w");

    // do stuff...

    if (error)
    {
        fclose(file);
        return;
    }

    try
    {
        // do stuff...
        throw FooException();
    }
    catch(...)
    {
        fclose(file);
        throw;
    }

    fclose(file);
}

This elegant solution is directly taken from The C++ Programming Language 3rd Edition by Bjarne Stroustrup. Create a lightweight class which represents the open resource, and make the destructor release the resource as the instance goes out of scope.

Implementation

This example is for an open file:

class OpenFile
{
  public:
    /** Constructor that opens file. */
    OpenFile(char *name, char *mode) { file = fopen(name, mode); }

    /** Constructor that uses an already open file ptr. */
    OpenFile(FILE *openFile) { file = openFile; }

    /** Destructor closes file in all cases. */
    ~OpenFile() { fclose(file); }

    /** 
     * Provide conversion operator so instances can be passed
     * directly to fprintf, etc.
     */
    operator FILE*() { return file; }

  private:
    FILE* file;
}

Use of the resource is simple:

void foo()
{
    OpenFile file("/tmp/log", "w");

    // do stuff...

    fprintf(file, "...trace info...\n");
}

The file is closed automatically in ~OpenFile(), no matter how foo() is exited. Even exceptions will cause OpenFile's destructor to be called as the instance goes out of scope.

Consequences

The advantages of Resource User are:

  • Ensures resource is released when it goes out of scope.
  • Code using the resource can be simplified accordingly.
  • Lightweight; no more storage required than standard resource descriptor (e.g. FILE*).
  • Can be directly passed to functions/methods that use the resource when the appropriate conversion operator is provided.

The disadvantages are:

  • Slightly more code upfront to write the new class. Not necessary for trivial uses of the resource.

See Also

Stroustrup, The C++ Programming Language, 3rd Edition, section 14.4

Comments

I was talking to a co-worker about this part of your blog. He pointed out that this can be really useful for profiling a function. Create a light class with a static member to keep track of the total amount of time spent in a function. Start a timer in the constructor and stop it and add the time to the static accumulator in the destructor. If you instantiate the class on the stack at the beginning of the function that you want to profile, then you have a simple way to profile that works no matter how the function that you're profiling exits.

Joel, that's a great variation of this pattern! Thanks for the contribution.

Post a comment