AutoPtr<> Class

The AutoPtr<> class is an extension of std::auto_ptr<> template class from the Standard Template Library. The main purpose of it is to destroy automatically some dynamically allocated resource (e.g. a memory, but it may be some other custom resource) after an AutoPtr<> object is destroyed.

Although this class is designed as a safe class that should prevent a resource leakage in your applications you should _understand_ how does it work because it has some _unusual_features_ that are not errors but may lead into big troubles if you are not aware about them. They are described below. But better explain also the source code, it is not large!

The Cleanup function is a function that deallocates a resource. This function has the following prototype:

typedef void CLEANUPFXN(void* p);
The Cleanup function MUST destroy the allocated resource inside itself in order to provide the proper class work and correct resource deallocation. For example it may call a 'delete' operator as an stl::auto_ptr<> destructor does:
void DeleteSingle(void* p)
{
 delete p;
}
But it may call a 'delete[]' operator or ::CoTaskMemFree() function or something else. The meaning of resource cleaning up is fully up to the programmer that use an AutoPtr<> class. The action should taken for resource cleaning up depends of the way the used resource is allocated. E.g. if you use an operator new[] for resource allocation you should use a delete[] operator in your custom Cleanup function. Some common Cleanup functions are already provided for you by the author.
They are:
::DeleteSingle() - uses a common operator delete,
::DeleteArray() - uses a common operator delete[],
::CloseAcDbObject(),
::AdsRelRb().
The two last functions are used in ObjectARX applications for AutoCAD to close AcDbObject or derived objects and to call ::ads_relrb() function. These are special functions for AutoCAD user extensions so their part of code will be included only if the ACRXAPP symbol is #defined.

Here are examples of AutoPtr<> usage and comments about:

#include "autoptr.h"
After we leave the block the memory is automatically deallocated because the ~p1 and ~p2 are called. This is the main advantage of AutoPtr<> usage. We never obliged to destroy the resource explicitly. This is as more useful feature as many branches are there in your code from those you can leave the scope of the explored block.
{
 AutoPtr<MyCustomClass, ::DeleteArray> p1(new MyCustomClass[100]);

 // Uses ::DeleteSingle() by default.
 AutoPtr<YourCustomClass> p2(new YourCustomClass);

 //Here we do something. The syntax of usage p1 and p2 is the common
 //C pointer syntax because the operators -> and * are overloaded:
 p1[30]->MyCustomMethod();
 (*p2).YourCustomMethod();
 p2->YourCustomMethod2();
}
You should avoid assignments of AutoPtr<> objects although the copy costructor and assignment operator are correctly overloaded. This may lead to surprising results:
{
 //p1 will "own" the allocated memory.
 //This means p1 will be responsible to memory deallocation.
 AutoPtr<char, ::DeleteArray> p1(new char[100]);
 strcpy(p1, "XXXXXXXXXXXX");

 {
  //Now p2 "owns" the memory, p1 is available too:
  AutoPtr<char, ::DeleteArray> p2(p1);    //Or p2=p1 that is almost the same.

  //The following two calls write to the same memory:
  strcpy(p1, "YYYYYYYYY");  //Ok!
  strcpy(p2, "ZZZZZZZZZZZZ");   //Ok!

 } //~p2, the memory is deallocated here.

 //!! Fatal Error - the memory is already deallocated before !!
 strcpy(p1, "HHHHHHHHHHH");
}
If you need to use the copy of stored pointer you should do this:
{
 //p1 will "own" the allocated memory:
 AutoPtr<char, ::DeleteArray> p1(new char[100]);
 strcpy(p1, "XXXXXXXXXXXX");

 {
  char* pChar = p1;

  strcpy(p1, "YYYYYYYYY");      //Ok!
  strcpy(pChar, "ZZZZZZZZZZZZ");    //Ok!
 } //No destructor is called, the memory is still valid.

 strcpy(p1, "NNNNNNNNNNNN"); //Ok!

} // ~p1. The correct cleaning.
You may use AutoPtr<> class if you have a function that returns a pointer as an argument by a reference or by a pointer. Such a function MAY NOT initialize a pointer to NULL, but don't worry: the implicitly called AutoPtr<>::Clear() function initializes it properly. (See the source code for nuances). void Fxn1(MyCustomObject*& pMyObject); void Fxn2(MyCustomObject** pMyObject);
{
 AutoPtr<MyCustomObject> pObject;    // = NULL, ::DeleteSingle() assumed.

 //Gets the first pointer.
 Fxn1(pObject.ByRef( /* bOwn = true */ ));

 //Gets the second pointer. The first pointer is 
 automatically cleaning.
 Fxn2(pObject.ByPtr( /* bOwn = true */ ));

} //~pObject, all is Ok.
//But no resource cleaning will be performed in this case
//(this feature is for advanced usage):
{
 AutoPtr<MyCustomObject> pObject;    // = NULL, ::DeleteSingle() assumed.

 //We receive a pointer but we aren't responsible for
 //deleting a received object!
 Fxn1(pObject.ByRef(false));

 if(pObject)
 {
  pObject->SomeMethod();
 }
}
//~pObject, but the memory is not deleted and in this example
//it will be lost if Fxn1() returned a newly created object.
Here is an another example: working with files. We usually opens a file calling fopen() and closes it using fclose(). In some cases we may forget to close a file.
//Now let's write a Cleanup function:
void CloseFileCRT(void* p)
{
 if(NULL != p)
 {
  fclose((FILE*)p);
 }
}

//We can now fopen() files and never fclose() them!
{
 AutoPtr<FILE, ::CloseFileCRT> pStream(fopen("somefile.txt", "r"));

 //Do something with an open file.

 if(anErrorOccured)
 {
  return;
 }  //Don't worry about fclose() - it is automatic!
}   //Don't worry about fclose() - it is automatic!
The previous list of examples of AutoPtr<> usage is not complete because I think there are many other ways how you may use this template class. This is up to your fantasy. I explained the main points only.

I think there is no meaning in deriving new classes from AutoPtr<>. If you don't agree with me you shold make the AutoPtr<> destructor virtual and then derive.

Here is a complete list of AutoPtr<> public member functions. See the AutoPtr<> source code to resolve raising questions.

//A standard constructor.
explicit AutoPtr(TYPE* p = NULL);

//A copy constructor. After its usage 'this' object 'inherites
//the resource owning' from 'c' object, and 'c' object always
//looses the resource owning.
explicit AutoPtr(const AutoPtr& c);

//An assignment operator. After its usage 'this' object 'inherites
//the resource owning' from 'c' object, and 'c' object always
//looses  the resource owning.
AutoPtr& operator=(const AutoPtr& c);

//Another assignment operator.
AutoPtr& operator=(TYPE* p);

//The destructor.
~AutoPtr();

//Type casting.
operator TYPE*() const;

//Dereference operator.
TYPE& operator*() const

//Logical NOT. Checks a stored pointer for NULL.
operator !() const;

//Member selection (pointer). Produces an irksome warning 4284 in VC++.
//You may disable this warning using the following line in common include
//file StdAfx.h: #pragma warning(disable: 4284)
TYPE* operator->() const;

//Clears the responsibility flag for resource deallocation.
//The stored pointer is still valid after this function is used.
//This function is NOT relative to COM IUnknown::Release() function!
TYPE* Release() const;

//Getting a safe pointer.
TYPE* Get() const;

//For functions that take a pointer as an argument by a reference.
//STL auto_ptr<> doesn't have this feature.
TYPE*& ByRef(bool bOwns = true);

//For functions that take a pointer as an argument by a pointer.
//STL auto_ptr<> doesn't have this feature.
TYPE** ByPtr(bool bOwns = true);

//Frees the pointer and then initialize class members.
void Clear(bool bOwns = false);

Downloads

Download source (AutoPtr.h) - 2 Kb