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


Comments

  • vc++

    Posted by Legacy on 12/26/2002 12:00am

    Originally posted by: sugunsg

    When I use stringstream in VC++ 6.0 I am getting the following error:
    fatal error LNK1104: cannot open file "SSTREAM.obj"
    Pls any one help me to solve this. I already put SSTREAM , strstream in project link settings.

    Reply
  • The new version has been posted at CodeProject site

    Posted by Legacy on 09/01/2001 12:00am

    Originally posted by: Dmitry Leonov

    http://www.codeproject.com/cpp/tautoptr.asp
    I'm going to post this version at CodeGuru too, but some time later (the article formatting takes too much time).

    Reply
  • function objects

    Posted by Legacy on 08/31/2001 12:00am

    Originally posted by: andi payn

    Why not use a C++ function object instead of a C callback
    
    function for the cleanup function? Then, you could just
    write:

    template<class T>
    struct DeleteArray {
    void operator()(T* t) { delete [] t; }
    };

    AutoPtr< MyCustomClass, DeleteArray<MyCustomClass> > p1(new MyCustomClass[100]);

    Or maybe just:

    AutoPtr< MyCustomClass, std::mem_fun(MyCustomClass::operator delete[])> p1(new MyCustomClass [100]);

    (Is that right? If not, you get the idea.)

    Reply
  • Class destructor not called

    Posted by Legacy on 05/24/2000 12:00am

    Originally posted by: Peter Schregle

    I was wondering if this class works as expected.

    If I'm using it as follows, the destructor is not called:

    CMyClass
    {
    ...
    ~CMyClass()
    { TRACE0("Destructor called\n"); }
    ...
    }

    ...

    AutoPtr<CMyClass> test(new CMyClass);

    When test goes out of scope, I could verify with the debugger that AutoPtr::Free and CLEANUPFXN are indeed called, but the delete operator inside CLEANUPFXN does not call the CMyClass destructor.

    I'm unsure, but I think this could be because CLEANUPFXN takes a void pointer, so the delete operator does not know to call the CMyClass destructor.

    I tried to use something like

    typedef template<TYPE> void CLEANUPFXN(TYPE*);

    but I can't get the syntax right.

    I could of course use my own cleanup function that casts the void back to CMyClass, but then templates are designed to avoid just that.

    Does anybody know where the problem is and how to get the syntax right?

    Best regards
    Peter Schregle

    Reply
  • The first (compatible) solution

    Posted by Legacy on 05/24/2000 12:00am

    Originally posted by: Dmitry Leonov

    The destructor is not called because 'delete' is applied to void
    
    pointer. You can write a special cleanup function for common base
    class in your class hierarchy. For example:

    #include "iostream.h"
    #include "autoptr.h"

    class Base
    {
    public:

    Base() {}
    virtual ~Base()
    {
    cout << "Base destructor" << endl;
    }
    };

    class Derived : public Base
    {
    public:

    Derived() {}
    ~Derived()
    {
    cout << "Derived destructor" << endl;
    }
    };

    void DeleteSingle_Base(void* p)
    {
    delete (Base*)p;
    }

    void main()
    {
    AutoPtr<Derived, DeleteSingle_Base> ap1(new Derived);

    } //ok, the virtual desructor does all work


    I'm sorry but a "template typedefs" aren't a part of current C++
    standard. You cannot write the code such as

    typedef template<class TYPE> void CLEANUPFXN(TYPE*);

    So to use the method I described your class hierarchy must have
    a common base class with a virtual destructor. If aren't - you'll
    need to write several cleanup functions with an explicit type
    casting inside each of them. Of course, this is not fine.

    This problem is not actual when you use AutoPtr<> with simple types:
    int, short, char etc. Simple types have no destructors.

    But let me some days to post the second and SMART solution!

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Protecting business operations means shifting the priorities around availability from disaster recovery to business continuity. Enterprises are shifting their focus from recovery from a disaster to preventing the disaster in the first place. With this change in mindset, disaster recovery is no longer the first line of defense; the organizations with a smarter business continuity practice are less impacted when disasters strike. This SmartSelect will provide insight to help guide your enterprise toward better …

  • Managing your company's financials is the backbone of your business and is vital to the long-term health and viability of your company. To continue applying the necessary financial rigor to support rapid growth, the accounting department needs the right tools to most efficiently do their job. Read this white paper to understand the 10 essentials of a complete financial management system and how the right solution can help you keep up with the rapidly changing business world.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds