Portable Guard Classes

Guarding other classes follows the same pattern. Assuming that all guards follow the pattern GuardXXX, where XXX is the name of a DB Interface Module class, you can use a simple macro to provide a portable interface, whether or not the compiler uses templates. The macro would look something like this:

 

#if compiler does not support templates

#define GUARD(Class, OBJECT) Guard ## Class guard__((OBJECT))

#else

#define GUARD(Class, OBJECT) Guard<Class> guard__((OBJECT))

#endif

The first macro concatenates the word Guard with the name of the class, RWDBConnection, and creates an instance of that class called guard__, initialized with the OBJECT (conn). The second macro simply instantiates an instance of class Guard with the type Class (Class = RWDBConnection). Even if your compiler or application does not support templates, you can use these macros in a portable manner as follows:

 

void doSomething(const RWDBConnection& conn)

{

// we’re going to use the connection so we’d better

// control access

GUARD(RWDBConnection, conn); // RWDBConnection supports the

// necessary interface.

// Do something on the connection.

// The mutex is released when the Guard instance goes out of

// scope.

}

Even when using the portable guard class template, you must still create a specialized guard class for each DB Interface Module object type you want to guard. For example, to guard an RWDBSchema, you have to create:

 

class GuardRWDBSchema {

.

.

.

}

This is necessary in addition to using GUARD(RWDBSchema, mySchema) in your code.