Click here to Skip to main content
15,886,830 members
Articles / Mobile Apps
Article

A Simple Template Based Smart Handle Class

Rate me:
Please Sign up or sign in to vote.
3.56/5 (5 votes)
4 Apr 20043 min read 47.6K   345   20   9
A template class that allows Win32 object lifetimes to be managed 'smartly', includes an example memory mapped file wrapper.

Introduction

There are many instances when programming Win32 where a HANDLE or other opaque entity is returned from an API call which must be subsequently released or closed with another API call. Managing these releases can get complicated, especially when an API call fails and cleanups are required, or in the event of an exception elsewhere in your code.

AutoClose is a template class that helps to manage HANDLEs and similar Windows objects that require releasing after use. The source code demonstrates two usages of the template, an elementary directory listing application, and an application that uses a memory mapped file class built with AutoClose to open and copy to the console a specified file.

Background

'Resource Acquisition is Initialization' seems to be the catch-all name for the concept of using the constructor and destructor of a class to tie the lifetime of an instance of that class to the lifetime of an external object. Most commonly implemented as 'Smart Pointers' to manage dynamically allocated memory and objects. On the face of it, a Smart Pointer is very simple to design and use, in practice, they are very difficult to get right and the user has to be concerned about copying, reference counting, passing to and fro functions and other semantic issues. The Standard C++ Library includes a limited, albeit very useful type of Smart Pointer, std::auto_ptr.

class Bar
{
    ...
} ;

void Foo ()
{
    std::auto_ptr<Bar> p ( new Bar ) ;
    // use Bar as necessary, return whenever,
    // Bar will get deleted on return from Foo
}

AutoClose is designed for a similar type of usage to std::auto_ptr either as a local variable within a function or as a member of a class. It is not a Smart Pointer per se, it doesn't offer operator-> for example. There are a couple of other articles on CodeProject that achieve a similar end, but I think this implementation is simpler if rather less interesting an adventure into C++ templates. The key feature is being able to write the name of the function you want called at 'release' directly into the template definition.

Using the code

AutoClose is defined thus:

template <typename T, BOOL ( WINAPI * F)( T ), T Invalid = 0> class AutoClose {}

The first template parameter, 'T' is the type of object to hold, the second 'F' the API function to call to release the object, which is assumed to take a single parameter of 'T' and return BOOL, and the third the value of the object that is treated as 'invalid'.

A typical usage might be:

WIN32_FIND_DATA fd ;
AutoClose<HANDLE, ::FindClose, 
   INVALID_HANDLE_VALUE> hFD ( ::FindFirstFile ( "*.*", &fd )) ;
if ( hFD )
{
    while ( ::FindNextFile ( hFD, &fd ))
    {
        ...
    }
}

Or perhaps:

class HasAnEvent
{
private :
    AutoClose<HANDLE, ::CloseHandle> hEvent_ ;
public :
    HasAnEvent ()
    {
        hEvent_ = ::CreateEvent ( 0, FALSE, FALSE, 0 ) ;
    }
    HANDLE Event ()
    {
        return hEvent_ ;
    }
} ;

This is the entire code for the AutoClose class:

template<typename T, BOOL ( WINAPI * F)( T ), T Invalid = 0> class AutoClose
{
private :
    T   t_ ;
    void Dispose ()
    {
        if ( t_ != Invalid )
            F ( t_ ) ;
    }
public :
    AutoClose () : t_ ( Invalid )
    {
    }
    explicit AutoClose ( T t ) : t_ ( t )
    {
    }
    ~AutoClose ()
    {
        Dispose () ;
    }
    AutoClose<T, F, Invalid>& operator= ( T t )
    {
        if ( t != t_ )
        {
            Dispose () ;
            t_ = t ;
        }
        return *this ;
    }
    T Detach ()
    {
        T t = t_ ;
        t_ = Invalid ;
        return t ;
    }
    operator T () const
    {
        return t_ ;
    }
    operator bool () const
    {
        return t_ != Invalid ;
    }
    bool operator! () const
    {
        return t_ == Invalid ;
    }
private :
    AutoClose ( AutoClose<T, F, Invalid> const& ) ;
    AutoClose<T, F, Invalid>& 
      operator= ( AutoClose<T, F, Invalid> const& ) ;
} ;

The constructor that takes a T argument is declared explicit to prevent code like this compiling:

int main ( int argc, char ** argv )
{
    AutoClose<HANDLE, ::CloseHandle> Handle = argv ;
    ...
}

The Win32 HANDLE type boils down to a void* and any pointer can be converted to a void*. By making the constructor explicit, the types must match completely, the above won't compile and so potential coding errors will be trapped. Unfortunately, this also prohibits that style of construction/assignment.

The copy constructor and operator= that take arguments of type AutoClose are declared private and not implemented. This is to help avoid ending up with two AutoClose objects each referencing the same handle yet without duplicating it, and hence 'closing' it more than required.

Detach allows the managed handle to be removed from the control of the AutoClose object.

HANDLE GetFile ( LPCTSTR sName )
{
    AutoClose<HANDLE, ::CloseHandle, 
       INVALID_HANDLE_VALUE> hFile ( ::CreateFile ( sName,... )) ;
    if ( hFile )
    {
        if ( !ValidateFileHeader ( hFile ))
        {
            return INVALID_HANDLE_VALUE ;
        }
        if ( !ValidateFileContents ( hFile ))
        {
            return INVALID_HANDLE_VALUE ;
        }
    }
    return hFile.Detach () ;
}

The operator bool and operator! allow the AutoClose object to be tested, whether the contained T is a valid handle, in a direct way. I suspect there are downsides to this but hopefully they'll show up at compile time....

Build Notes

I've only built and tested this class and sample programs with Visual C++ 7.1 on Windows XP. I would expect them to build on earlier versions but I haven't tested it or supplied solution files.

References

Related Code Project articles:

License

You can do what you like with this class and example code except remove the copyright or sell the source.

History

First release - April 5 2004

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.

A list of licenses authors might use can be found here


Written By
Web Developer
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralQuite close to Richter solution Pin
Richard GILL29-Mar-12 4:09
Richard GILL29-Mar-12 4:09 
Generalwont work on 6.0 Pin
sahn05-Apr-04 21:41
sahn05-Apr-04 21:41 
GeneralRe: wont work on 6.0 Pin
Paul Ranson6-Apr-04 1:20
Paul Ranson6-Apr-04 1:20 
GeneralRe: wont work on 6.0 Pin
KevinHall6-Apr-04 5:35
KevinHall6-Apr-04 5:35 
GeneralRe: wont work on 6.0 Pin
Peter Hancock6-Apr-04 16:11
Peter Hancock6-Apr-04 16:11 
GeneralGood Pin
Abin5-Apr-04 18:19
Abin5-Apr-04 18:19 
GeneralRe: Good Pin
Paul Ranson6-Apr-04 1:25
Paul Ranson6-Apr-04 1:25 
GeneralRe: Good Pin
.:floyd:.15-Apr-04 16:44
.:floyd:.15-Apr-04 16:44 
GeneralRe: Good Pin
Paul Ranson19-Apr-04 2:06
Paul Ranson19-Apr-04 2:06 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.