Sunday, 21 June 2015

Efficient Use of Destructors to Prevent Resource Leaks with examples in C++

Efficient Use of Destructors to Prevent Resource Leaks with examples in Cpp with example

When the exception thrown by a program that is not caught, program execution immediately stops.
In C language this situation is handled by setjmp and longjmp.
The longjmp behaves differently with the C++ language. It fails to call destructors for local objects when it adjusts the stack.

How to use destructors to prevent resource leaks?

Yes, we need to learn about this clearly, to avoid memory leaks.
A reasonable approach to this task is to define an abstract base class, ANIMAL, plus concrete derived classes for Dogs and Cats. A virtual function, process property, and handles the necessary species-specific processing:

class ANIMAL {

public:

virtual void GetProperties () = 0;

...

};

class Dog: public ANIMAL {

public:

virtual void GetProperties ();

...

};

class Cat: public ANIMAL {

public:

virtual void GetProperties ();

...

}

  This is a perfect job for a virtual constructor. For our purposes here, the function’s declaration is all we need:
// read animal information from inStrm, then return a pointer.
ANIMAL * readANIMAL(istream& inStrm);


The final function looks like this:
void GetPropertiess(istream& dataSource)

{

while (dataSource) { // while there’s data

ANIMAL *pcAnimal = readANIMAL(dataSource); // get next animal

pcAnimal ->GetProperties(); // process adoption

delete pcAnimal; pcAnimal = NULL; // delete the object

}

// readANIMAL returned

}

This function loops through the information in dataSource, processing each entry as it goes. We need to remember that delete pcAnimal at the end of each iteration.
This is necessary because readANIMAL creates a new heap object each time it’s called.
Without the call to delete, the loop would contain a resource leak.

Now consider what would happen if pcAnimal->GetProperties threw an exception. GetPropertiess fails to catch exceptions, so the exception would propagate to GetPropertiess’s caller. In doing so, all statements in GetPropertiess after the call to pcAnimal->GetProperties would be skipped, and that means pcAnimal would never be deleted

How to use Destructors to Prevent Resource Leaks?

Destructors of the class is used to destroy the allocated memory for the member variables of the class, when the class goes out of the scope
As a result, anytime pcAnimal->GetProperties throws an exception, GetPropertiess contains a resource leak.
void GetPropertiess(istream& dataSource)

{

while (dataSource) {

ANIMAL * pcAnimal = readANIMAL(dataSource);

try {

pcAnimal ->GetProperties();

} catch (...) {

// catch all exceptions

delete pcAnimal; pcAnimal = NULL; // avoid resource leak when an exception is thrown

throw; // propagate exception to caller

}

delete pcAnimal; pcAnimal  = NULL; // avoid resource leak when no exception is thrown

}

}


Regardless of whether we leave GetPropertiess by a normal return or by throwing an exception, we need to delete pcAnimal. That’s because local objects are always destroyed when leaving a function, regardless of how that function is exited. Our real concern, then, is moving the delete from GetPropertiess into a destructor for an object local to GetPropertiess.
The solution is to replace the pointer pcAnimal with an object that acts like a pointer. That way, when the pointer-like object is destroyed, we can have its destructor call delete. Objects that act like pointers, but do more, are called smart pointers.

Example for auto_ptr:
template<class T>

class auto_ptr {

public:

auto_ptr(T *ptype = 0): ptr (ptype) {} // save ptr to object

~auto_ptr() { delete ptr; } // delete ptr to object

private:

T *ptr; // raw ptr to object

}


The standard version of auto_ptr is much fancier, and this strippeddown implementation isn’t suitable for real use but the concept behind it should be clear: use auto_ptr objects instead of raw pointers, and you won’t have to worry about heap objects not being deleted, not even when exceptions are thrown.
Using an auto_ptr object instead of a raw pointer, GetPropertiess looks like this:
void GetPropertiess(istream& dataSource)

{

while (dataSource) {

auto_ptr<ANIMAL> pa(readANIMAL(dataSource));

pcAnimal->GetProperties();

}

}

This version of GetPropertiess differs from the original in only two ways. First, pcAnimal is declared to be an auto_ptr<ANIMAL> object, not a raw ANIMAL* pointer. Second, there is no delete statement at the end of the loop. That’s it. Everything else is identical, because, except for destruction,auto_ptr objects act just like normal pointers.

Example for using Destructors to Prevent Resource Leaks:

The idea behind auto_ptr — using an object to store a resource that needs to be automatically released and relying on that object’s destructor to release it — applies to more than just pointer-based resources. Consider a function in a GUI application that needs to create a window to display some information:
// this function may leak resources if an exception is thrown
void GetInfo(const Information& info)

{

WINDOW_HANDLE win(createWindow());

display info in window corresponding to win;

destroyWindow(win);

}

If an exception is thrown during the process of displaying info in win, the window for which win is a handle will be lost just as surely as any other dynamically allocated resource.

The solution to avoid above situation is to create a class whose constructor and destructor acquire and release the resource:

class WindowHandle

{

public:

WindowHandle (WINDOW_HANDLE handle): win (handle) {}

~WindowHandle () { destroyWindow (win); }

operator WINDOW_HANDLE () { return win; } // see below

private:

WINDOW_HANDLE win;

WindowHandle (const WindowHandle&);

WindowHandle& operator= (const WindowHandle&);

}

This looks just like the auto_ptr template, except that assignment and copying are explicitly prohibited, and there is an implicit conversion operator that can be used to turn a WindowHandle into a WINDOW_HANDLE.
Given the WindowHandle class, we can rewrite GetInfo as follows:
// this function avoids leaking resources if an
// exception is thrown
void GetInfo(const Information& info)

{

WindowHandle win (createWindow());

// write the code to display info in window corresponding to win;

}

Even if an exception is thrown within GetInfo, the window created by createWindow will always be destroyed.

No comments: