Upcoming Events
Unite 2010
11/10 - 11/12 @ Montréal, Canada

GDC China
12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010
12/24 - 12/27  

GDC 2011
2/28 - 3/4 @ San Francisco, CA

More events...
Quick Stats
80 people currently visiting GDNet.
2406 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!
Link to us Events 4 Gamers
Intel sponsors gamedev.net search:

  Contents

 Termination
 Handlers

 Performance
 and Flexibility


 Comment on
 this article

 Printable version

 


Introduction

I recently read Vadim Kokielov's article on Windows' SEH, but I think that there were some unfair, and perhaps hasty, conclusions reached in the comparison of Windows' SEH with C++ EH. My article is intended to be a rebuttal and is provided merely for additional insight into the topic of C++ EH. It is not intended to be completely unbiased.

If anyone can correct me on these arguments and suggestions (particularly Vadim) I would appreciate it and post the conclusions as updates here, or perhaps as a part 2 of this article, if the GDnet staff is willing to format it (Ed.- we are). Please do not post a reply intended for me on the GDNet message boards.

Any email I get containing any of the following: violent replies, wild assumptions, and any arguments related to C vs. C++ or OOP vs. Structured Programming will be deallocated immediately :) and no credit will be given to the author of such crap in the event that he/she manages to provide useful information.

Onward to the rebuttal. :)

Termination Handlers

In comparison with C++ exception-handling, termination handlers really only matter for resources that will not be deallocated by destructors (i.e., temporary resources dynamically allocated by non-C++ code from inside a function, or from inside a constructor). In all other instances, a properly-written destructor will be able to clean it up.

For such special instances, one can easily write a class template that will take advantage of the destructor calls made when local variables go out of scope. It only has to be written once (per programmer lifetime :), plus a simple deallocator (in most cases, a single function call). I would remind you that although the deallocator has to be written (once per type, not per instance) and the template class instantiated in C++ EH, in SEH you would have to write the deallocation function calls in your __finally block anyway.

Examples

The class template need only be a slightly modified version of std::auto_ptr. For example,

namespace auto
{
  namespace deallocation
  {
    template <typename T>
    struct heap { void operator () (T* const pointer) { delete pointer; } };

    struct handle { void operator () (HANDLE const handle) { CloseHandle(handle); } };
    struct bitmap { void operator () (HBITMAP const handle) { DeleteObject(handle); } };
    struct window { void operator () (HWND const handle) { DestroyWindow(handle); } };
    struct file { void operator () (FILE* const handle) { _fclose(handle); } };
    struct com_object { void operator () (IUnknown* const handle) { handle->Release(); } };

    // etc.
  };

  template <typename T, typename D = deallocation::heap<T> >
  class handle
  {
    T* pointer;
    D deallocate;

  public:
    handle(T* const pointer) : pointer(pointer) {}
    ~handle() { if( pointer ) deallocate(pointer); }
    // ...
  };
};

Then you simply use it similarly to std::auto_ptr, substituting any custom deallocators when the need arises:

void myclass::myclass(const char* const filename)
{
	auto::handle<some_big_class> bc = new some_big_class;
	auto::handle<FILE, auto::deallocation::file> fp = _fopen(filename, "r");

	// bc and fp are automatically closed whether or not an exception is thrown
}

Personally, I think that std::auto_ptr should have been written to support custom deallocators. Note that a partial specialization of auto::handle should be written to include Windows' handle types and all other types that require the first template argument be a pointer type.

Conclusion

This solution has the following benefits over SEH:

  1. Class destructors become analogous to the __finally blocks.
  2. Deallocation code (including its logic) only has to be written once per type, not per instance (as with SEH).
  3. The habit of declaring resources as having automatic deallocation is easier to obey than declaring them normally and then remembering to clean them up.
  4. The handle class is extensible in any way a normal C++ class is, while SEH must remain tied to structured programming (hence its name).
  5. C++ EH and auto::handle are portable across platforms; SEH is not.



Next : Performance and Flexibility