std::auto_ptr makes VCL less annoying

Index

If you're like me, you believe that temporary variables should be allocated on the stack. This is because C++ guarantees that stack variables will be destroyed, even in the event of an exception. Obviously, this is a nice feature, because you don't have to remember to delete your temporary variable. Unfortunately, if you want to use a VCL component as a temporary variable, you've got a problem. You see, VCL objects may only be allocated on the heap, via the new keyword. This is an "extension" to C++ that I find incredibly annoying.

This can easily lead to resource leaks. Suppose you allocate an object and then call a member which can throw an exception. If you don't catch the exception and delete your object, then you've got a leak. But, you say, not catching that exception is a bug. Well, I hate to break it to you, but you're wrong. One of the main reasons for having exceptions is to allow for centralized error management. If the routine you're writing is not concerned with the exception, then it doesn't need to catch it, and should not catch it. This reduces the complexity of your code and allows only those routines that are concerned with errors to handle them.

Suppose that after you allocate an object, you check an error code from another function and return before deleting your object. Guess what; you've also got a leak. Well, you say, not deleting the object before returning is a bug. You're right. It is a bug. And that bug could have been easily avoided if your object were allocated on the stack instead of on the heap. But VCL won't let you do that, because "Borland Knew Better."

Luckily, the C++ Standard Library contains a template class, auto_ptr, which will make any pointer object, including VCL's, be destroyed automatically. So, if you need a VCL object only temporarily, store its address in an auto_ptr.

How does auto_ptr work? Basically, it has a member of type pointer-to-the-template-argument. When you construct the auto_ptr, this member gets initialized to NULL. Any time you assign a pointer to your auto_ptr object, it takes "ownership" of the pointer. All this means is that when ~auto_ptr gets called (which happens when auto_ptr falls out of scope), the pointer that auto_ptr owns will be deleted. Note that auto_ptr can only own a single pointer at a time. If you assign a new pointer to an auto_ptr that already owns a pointer, it will delete the old pointer before accepting the new one.

Example:

/* This sample shows how to use TRegistry and auto_ptr to safely access the registry and not accidentally generate any memory leaks. Note that if the registry key HKEY_CURRENT_USER\Software\Kast\Example does not exist, then the call to _registry->OpenKey(...) will generate an exception. However, because C++ guarantees that _registry will be destroyed, the TRegistry object that _registry "points" to will also be destroyed, and no leaks will occur. */ #include <vcl.h> #include <memory> #include <Registry.hpp> #include "TMyForm.h" void __fastcall TMyForm::StoreConfiguration( TObject* Sender ) { std::auto_ptr< TRegistry > _registry( new TRegistry ); _registry->OpenKey( "Software\\KAST\\Example" , false ); _registry->WriteString( "Sample" , "Hello" ); }