Introduction

Sometimes you want to automatically execute some code at the end of your code block, to free memory, free resources, unlock files, ... Some of the standard cleanup methods have already been foreseen by the C++ standard, STL or your C++ compiler. e.g. Auto-pointers (or smart-pointers) provide a way of making sure that your memory is freed at the end of your code block.

How such an automatic cleanup is implemented

The automatic cleanup is implemented by a separate class, whose destructor automatically performs the necessary cleanup. e.g. The following code shows the definition of a class that performs file locking. The constructor will automatically lock the file. The destructor will unlock it.

What if cleanup is not performed in a destructor?

Suppose we have a class that contains (besides many other methods) the following two methods: increment and decrement. If a function or method calls increment(), it is also responsible for calling decrement at the end, like shown in this example:

Now, what if the function forgets to call decrement at the end of the function? Or what if an exception is thrown in the function? Yep, MyClass will probably go bananas, incorrect data will be shown by the application, it will crash, ... The solution is simple, but cumbersome. Simply write a class in which the constructor will call increment, and the destructor will call decrement, like this:

In beginning of main
FirstMethod, value is 1
In sub block
LastMethod , value is 1
FirstMethod, value is 2
In sub block
LastMethod , value is 2
At end of main

And this proves that FirstMethod and LastMethod are called correctly.

const methods

After having written these two nice templates, I started using them right away in a new class I wanted to write. My class had two methods - lock() and unlock() - that locked and unlocked a data structure (for use in a multithreaded environment). My class was called ThreadSafeList (maybe more of this in a later article).

What I did was defining a Locker class like this:

typedef AutoRunner<ThreadSafeList,lock,unlock> Locker;

My methods then simply had to create a Locker on *this like shown here:

void clear () {Locker locker(*this); stltype::clear();}

And indeed this correctly worked ... until I wrote a const method, like this:

This message means that the lock method tries to modify my data member that manages the locking (in this case a CRITICAL_SECTION) and this is simply not allowed in a const method.

So the last step we need take, is to make our critical section mutable, like this:

mutable CRITICAL_SECTION m_criticalSection;

Et voila, it works.

Disadvantages and improvements

The biggest disadvantage is that the methods passed to the template cannot have arguments. That can probably be solved by adding more template classes, but I did not wanted to go into that.

Alas, the second and third templates do not compile in Microsoft's Visual C/C++ 6.0, although they compile correctly in Visual C/C++ 7.1 (not sure about 7.0). This shows that 7.1 will be a much better compiler than 6.0.

Another improvement might be to make the methods that should be called in pairs (in my example FirstMethod and LastMethod) private in the class, and making the template class a friend of it. That guarantees that nobody else calls FirstMethod and/or LastMethod explicitly, with the danger of not correctly executing them as a pair.

Do you like templates?

This article is yet again a demonstration on how templates can be used to solve problems in which you have to write the same type of class over and over again. Simply write the template (once!), then use it (or typedef it to make it easier for the caller).

History

28 March 2003: Original version

20 June 2003: Added AutoRunnerConst

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

As said in the article, the code only compiles with Visual Studio .NET (7.1).
It doesn't compile with Visual Studio 6 because that version has only limited template support.
It's possible that it also compiles with the GNU compiler, I didn't check that recently.

Two other things from Boost will solve several issues in this article. First, Boost.Function (http://www.boost.org/doc/html/function.html) provides a replacement for those function signatures which lead to problems with member functions. Further, it works for VC6. Second, Boost.Bind (http://www.boost.org/libs/bind/bind.html) or Boost.Lambda (http://www.boost.org/libs/lambda/doc/index.html) can be used (assuming you use Boost.Function instead of sticking with the hard code function signatures) to work around not being able to pass parameters.

I think there's a small flaw in your code: as you haven't defined copy constructors and assignement operators for AutoRunner and AutoRunnerStatic, they will get default ones, which is in contradiction with the intended semantic, as this sample shows:

You'll get one increment and two decrements this way. I guess the most sensible solution is to ban copy and assignments of these objects by simply declaring their copy constructor and assignment operator private (you need not actually define them).

What do you think is best regarding copy constructors and assignment operators:
* Always make them private (without implementation) unless you really need them and then provide a decent implementation or check whether the default implementation works correctly.
* Always think about providing a correctly working copy constructor and assignment operator (or use the default)

Ufff... Well, I'd say that the semantics of a given class almost always dictate what to do about copying and assignment --be it using default behavior, provide your own or ban it. What's wrong is not thinking about it. So, design your class, think about what you want to them to behave when copying and assigning around and make your choice.

Patje wrote:What do you think is best regarding copy constructors and assignment operators:

That depends on the class design. If your class is intended to be a concrete ("value") type, then by all means provide both copy constructor and assignment operator (or leave the default ones if that is what you want). If it is a part of some OO hierarchy, than you will probably want to make them private, without implementation.

I use this pattern for transaction control to ensure that transactions either commit or rollback.

To use arguments, you could pass functors, (function objects implementing operator() ), instead of function pointers. This way, you can actually write all the arguments and pass them in in the constructor. The usage essentially remains the same.

Andrei Alexandrescu has something about function pointers and functors in Modern C++ Design.

5 from me. I like anything that uses templates intelligently.

And they still ran faster and faster and faster, till they all just melted away, and there was nothing left but a great big pool of melted butter

"I ask candidates to create an object model of a chicken."-Bruce Eckel