Thursday, July 31, 2008

Resource control with scope guard

My friend Ozgur Macit asked me if there is a way to implement auto pointer design pattern for ANSI C functions like malloc and free.

Here is the traditional way to write a function:

int traditional()
{
char*ptr = (char*)malloc( sizeof(char) );

//check the return value if ptr is NULL or not

//use this ptr in several operations
//if statements, switch statements, pass as argument to other functions etc.

free(ptr);
return 0; //EXIT POINT

}

if function returns from the EXIT POINT, we all know that "free" function gives the memory back. However what if the function throws in the middle of the execution, or returns for some reason. Then we should handle all of these cases and write the free(ptr); statement before return points. This makes code less maintainable as well as more error prone.

Lets implement our scope guard class which will provide a safe and easy way to prevent this memory to be leaked.
What will we do is basically creating a local object which will be destroyed when it goes out of scope. That is way i call it scope guard.
It is clear that, when it goes out of scope, it should call "free" function with the necessary parameter.

class scope_guard{

void* _MyPtr;

public:
scope_guard( void* ptr ): _MyPtr( ptr ){}
~scope_guard(){ free(_MyPtr); }
};

It is pretty straightforward, isn`t it? It takes the pointer and frees it when local object goes out of scope.

Here is a simple usage:

int contemporary(){
char*ptr = (char*)malloc( sizeof(char) );
if(!ptr){
//log error message and return error code
}
//here we go..
scope_guard guard( ptr );

//use ptr in several operations...

return 0; //no explicit call to free. guard object will do this for us..
}

You should create the guard object after checking the malloc result and BEFORE using this pointer in any operations. Because semantic of creating a guard object is providing an error handling mechanism. if you use ptr in any operation before creating guard object and if this operation fails, you are in trouble now..

Note that the class i wrote here is a simple example for demonstration purpose. You can add template and function pointer concepts to this class to design a generic scope guard class which can work for lots of functions. Clearly, this one is craeted for only "malloc" and "free" pair.
You can also put copy constructor, assignment operator as private methods since they are meaningless in this case.

Thanks for reading this post, any comments will be appreciated.

8 comments:

Özgür Macit said...

Emre, I was actually looking for a solution in ANSI C - I mean no classes. No classes at all :) I think C is not a "classy" programming language :P

emreknlk said...

You can always use C++ for writing C style code. It has backward compatibility. Apart from that, if you are writing in ANSI C then you dont have to worry about exceptions. You should be careful in "return" statements.
The posts i wrote, are examples of RAII which comes with OO languages such as C++.
You can look at wiki for more information about RAII.
http://en.wikipedia.org/wiki/Resource_acquisition_is_initialization
One thing i want to add that; if you are not writing OS level code, i don`t recommend using C. C++ is much better :)

qp said...

emre,could you tell me what does ANSI stand for:P everytime i read your blog i start to think that i am an alien:D i know one day i will see something that i ve heard about it, in your blog:D i will be waiting for that post..:p

emreknlk said...

http://www.seslisozluk.com/?word=ansi :)

Burcu Dogan said...

Please also remember to assign NULL to ptr /* ptr = NULL; */ after freeing contents that was being referenced by ptr. It's going to save you from crucial mistakes such as trying to access a deallocated memory block.

emreknlk said...

Since ptr will go out of scope we can`t really assign it to NULL in this case.

Burcu Dogan said...

Sure, just a reminder :)

Kotesh said...

In destructor, you may want to check if *ptr=NULL. If so, do not free it.