Sunday, March 27, 2011

Step-motherly treated C++ feature : Smart Pointers

        
     Raw pointers pointing to location acquired from free store must always return the resources to the free store, else the classical problem of memory leak prevails. Let's work on the issues with the following code snippet -
void foo()
{
    int *rawPtr = new int(100) ;
    
    // Some functionality involving complex code

    delete rawPtr ;
}
        There are at least three situations, which I can think of, where the above code would fail to deallocate the resources "rawPtr" is pointing to.
  1.     What if an exception rise in the complex part of the code ?
  2.     What if there is an early return in the complex part of the code ?
  3.     What if you accidentally placed another delete statement on rawPtr ?
        In first two situations, statement "delete rawPtr ;" never executes and there is memory leak which we never expected to have. Deleting a dangling pointer behavior is undefined and happens in the last case. C++ programmers should always take the advantage of smart pointers: std::auto_ptr to handle the raw pointers, which is the simplest smart pointer in the family. Now lets work on same snippet using std::auto_ptr which is available in the standard header "memory" and defined in the "std" namespace.
void foo()
{
    int *rawPtr = new int(100) ;
    std:: auto_ptr<int> safePtr(rawPtr) ;

    (*safePtr) = 50 ;   // This is same as (*rawPtr) = 50 ;
   
    // Some functionality involving complex code

} // safePtr out of scope
What actually is the statement doing: std:: auto_ptr<int> safePtr(rawPtr) ;
       
        "safePtr" is an auto pointer parameterized on int type, signifying the capability of owning the address of location, that can hold an int, acquired from free store. Here it takes the ownership of the raw pointer, "rawPtr",  pointing location. In any case if the "safePtr" goes out of scope, it returns the resource it owns to the free store safely avoiding memory leak. Notice that, there is no need to explicitly mention to deallocate the resources using the "delete" statement. Using "delete" statement turns down the whole purpose of using smart pointers. In fact, the whole snippet can me minimized avoiding the usage of raw pointers at all.
void foo()
{
    std:: auto_ptr<int> safePtr(new int(100)) ;

    (*safePtr) = 50 ;
    // Some functionality

} // safePtr out of scope
The same can be done on user-defined types too.
class foo
{
    std:: auto_ptr<int> safeMember ;
    public:
        foo( int number=10 ) : safeMember( new int(number) )
        {}
        inline int getNum() const
        {
            return (*safeMember) ;
        }
};

int main()
{
    std:: auto_ptr<foo> safePtr( new foo ) ;  // foo is a user-defined type
    std:: cout<< safePtr->getNum() << "\n" ;
                     // ^^ Notice the use of member access operator -> on safePtr
    return 0 ;
}
    release
         release() releases the ownership of the memory location std::auto_ptr owning and returns a pointer to the location. In C++, it's the responsibility of the caller to catch the return value. It is completely valid not to collect the return value of release() but at the cost of never being able to resolve the memory leak issue.
void foo()
{
    
    std:: auto_ptr<foo> safePtr( new int(100) ) ;
    int *rawPtr = safePtr.release() ;
    delete rawPtr ;  // Definitely necessary

}  //  safePtr goes out of scope but does nothing like deallocation since the resources are released
    reset
        reset() resets the ownership of std::auto_ptr to take the ownership of new location. So, when an std::auto_ptr is reinitialized/reassigned to take the ownership of new location -
  •     It first deallocates the resources, if at all it owns anything
  •     Then, takes the ownership of new location.
void foo()
{
    std:: auto_ptr<foo> safePtr( new int(100) ) ;  // safePtr owns memory location, say M1
    safePtr.reset( new int ) ;   // safePtr now owns memory location, say M2
    safePtr.reset() ;
}
Pitfalls
    
    1.    Assignment operation is similar to a reset() operation, in this snippet. It first deallocate the resource it owns and takes the ownership of new resource. Here, the assignment operation results "rawPtr" dangling.
void foo()
{

    int *rawPtr = new int(100) ;
    std:: auto_ptr<foo> safePtr(rawPtr) ;

    int *anotherRawPtr = new int(50) ;
    safePtr = anotherRawPtr ;  // Assignment operation

    (*rawPtr) = 25 ;  //  Undefined behavior

}  // safePtr out of scope
    2.    Should be careful while passing a raw pointer to a function whose argument is of type std::auto_ptr and return type is void.
void foo(std:: auto_ptr<foo> safePtr)
{
    
    // ....

}  // safePtr goes out of scope and causes to deallocates the argument's resource it owned

int main()
{
    
    int *rawPtr = new int(100) ;
    foo(rawPtr) ;  // Upon return of foo, causes rawPtr dangling
    (*rawPtr) = 50 ;  // Undefined behavior

}
Conclusion

        Why should a programmer think of memory leaks when the run time is capable of dumping them after program termination? With memory leaks, program is laying off memory locations on a free way which no other process can have access to until the program's termination. Besides that it is not a good programming practice to rely on run time when programmer can efficiently handle the situations. Smart pointers are useful for the purpose and “std::auto_ptr” should be used to handle raw pointers. It provides an extremely safe way of avoiding memory leaks in any unwarranted situations. They deallocate the resources automatically ( of course nothing is automatic and some thing on our behalf is going behind the scenes ) they are owning once they are out of scope and the name aptly suits justifying it.

PS: One can easily check for memory leaks on a Visual Studio environment in Debug mode. Compiled the below snippet on Visual C++ 2010 Express Edition.

#define _CRTDBG_MAP_ALLOC

#include <crtdbg.h>

int main()
{
    
    int *rawPtr = new int(100) ;
    // Purposefully not deallocating the rawPtr owned resources from free store
    _CrtDumpMemoryLeaks() ;
    return 0;

}
Output:
....
Detected memory leaks!
Dumping objects ->
{56} normal block at 0x006C3250, 4 bytes long.
Data: <2 > 32 00 00 00
Object dump complete.
The program '[6160] blogPostMemoryLeaks.exe: Native' has exited with code 0 (0x0).

Thursday, February 10, 2011

C++ - Rule of Three

We copy the contents of one instance to another many a times, with out knowing undefined behaviour which it may some times lead to. Let's work on with an example -
class foo
{
   int* ptr;
   int  var;

    public:
    foo()
    {
        var  = 10;
        ptr  = new int;
        *ptr = var;
    }

    ~foo()
    {
       delete ptr;
    }
};
The good things about this very simple foo interface is -
  1. It's using constructor to initialize it's member variables.
  2. It's giving back the resources to the free store in the destructor acquired through operator new in the constructor. It's always a good programming practice , infact it is a must, to return the resources if the programmer is managing resources. Now, though this interface seems to be very simple can lead to very complicated problems. Lets see what happens with the following code snippet -
foo objOne;
foo objTwo = objOne;
Now the intention of second statement is to copy the contents of objOne to objTwo, so that each have their own set of variables. So, the construction of objTwo happens with the default copy constructor, provided by the compiler, is called to do a member-wise copy. Both the default copy constructor, copy assignment does the same operation but which one is called depends on the statement which we shall discuss in another post. The problem is with the pointer variable because the values pointed by the pointer aren't going to be copied. Instead, the content of the pointer is going to be copied. And this means both pointer variables of two instances are pointing to the same location which is definitely not what our intention is with the second statement.The potential problems that may be faced with default copy construction in this interface is - " What happens if objOne deallocates the resources managed by it ?". We have a dangling pointer variable in objTwo. So, this is where the Rule of Three comes in to the picture.
What is Rule of Three ?
If you feel the interface needs either a -
  1. Copy Constructor
  2. Copy Assignment Operator
  3. Destructor
then, the interface may require all the three. Now, with this rule in mind, lets modify the interface foo.
class foo
{
    int* ptr;
    int  var;

    public:
    foo()    // Default Constructor
    {
        var  = 10;
        ptr  = new int;
        *ptr = var;
    }

    foo( const foo& obj )  // Copy Constructor
    {
        ptr = new int;
        ptr = obj.ptr;
        var = obj.var;
    }

    foo& operator= ( const foo& obj )  // Copy Assignment
    {
        if( this != &obj )
        {
            delete ptr;
            ptr = new int;
            ptr = obj.ptr;
            var = obj.var;
        }
        return (*this);
    }

    ~foo()  // Destructor
    {
        delete ptr;
    }
};
On implementing Rule of Three to the interface foo, both objOne and objTwo will have their member variables owning their own memory locations. So, the deallocation of resources by one instance isn't going to affect the other. Thus, avoiding the famous "Undefined Behaviour" of the programming paradigm. But as long as the interface is away from raw pointers, Rule of Three is likely not a concern.
PS: Some of the content mentioned here might be wrong. I welcome suggestions to improve the post. Thanks.

Wednesday, March 31, 2010

Healthy to Mac turns sick on Windows !!

“ What the f**k ? “, “ Are you kidding me? “, “ What !!! ”, “ That’s very stupid !” are the sort of sentences I often listen from programmers when I pass by them at my work place. Being a novice programmer, I am puzzled and a moment think of what these guys are reprimanding at. Just out of curiosity asked one of them- “ Whom do you guys usually reprove at while programming ? “. With eyes wide open he replied, “ Its the compiler “. His answer wasn’t satisfying enough to convince until I found myself in their shoes.

Mesh sub-division is the assignment task of my graphics course. Being a mac user, I program in Xcode, an IDE similar to Visual Studio(VS) on Windows. Everything was fine until I tested the code on VS-2008. The compiler complained a run-time error and was more than puzzled to find what healthy to Mac is sick on Windows.

void

MeshClass :: GetLastVertexID( void )

{

std::list<tVertex> :: iterator iter( m_verts.end() );

lastVertexID = (*iter)->id() ;

}

Trying to dereference the end() of any list/vector is definitely a run-time error and was puzzled to see a non-garbage value present in the variable lastVertexID when debugged on Xcode. Cleaning and rebuilding the project didn’t either help the Xcode’s compiler to recognize this run-time error. The VS-2008 compiler is intelligent enough in preventing me not to dereference the end of the list. However, later rectified the mistake by decrementing the iterator once before dereferencing -

void

MeshClass :: GetLastVertexID( void )

{

std::list<tVertex> :: iterator iter( m_verts.end() );

--iter ;

lastVertexID = (*iter)->id() ;

}

The instant VS-2008 compiler complained, I was out of all foul and filthy statements that I possibly could scold. I was reluctant enough even to see the run-time error message and rather spent time in praising Mac over Windows. After much midnight oil burnt in Mac-praising, found how possibly can a Mac compiler could safely run such unsafe code. The assignment not only learnt me lesson of how compilers are different from each other but also why programmers should have many compilers on friends-list to be successful.

Results :

Saturday, March 13, 2010

" Broken Silence "

Too many americans give a voluntary-hearty-smile but never a voluntary-hearty-talk with me. Often, I think of what and how would the gap between us bridged. The hesitation of how would they receive makes me dumb even when I get a chance to break the " Silence ". Heard a lot from my friends saying americans mingle too soon when you take the brave step of opening the chat. Sometimes I convinced myself to give a try but " Silence " between us wins. Promisingly thinking of a day they asking me help would make myself win over my " Silence ". But, never thought of a year's back lucky draw won amount sponsored by Sidelines to the Office of International Affair's Coffee Hour would bring the opportunity.
While was sitting in the corner of a library came to me a Shreveport girl asking - " Do you know how to make copies over the Xerox machine ? ". It was the moment where my " Silence " was dumb enough than my strong desire to talk. I neither made use of that facility nor at least went into that room but took the advantage of helping her though being helpless. But once heard from a friend of self servicing xerox facility available in the campus provided Cajun Cash available in your account. Momentarily wished several times of the left over lucky-draw-won- spent-amount should be sufficient enough to help her and her friend. Luckily, "Silence" didn't had the last laugh this time.
It should be at least a 15 minute chat of self introduction, education-system in comparison with my country, India, future plans etc.,. Americans speaking to me by themselves is joyous enough at the moment causing pay less attention to what they actually spoke of. They paid owed amount but at the end came a sentence which left me startled. The Shreveport girl asked with her hands wide open - " Give me a hug ". How could an ardent willingness just to speak with an american feel if ended with such strange, warm feeling isn't that I could put into words. But I strongly believe, the Shreveport girl left-over impression would make myself to open conversation to leave me as a "Winner" over my "Silence" when met an american next time.

Saturday, July 18, 2009

King Size School Life

Reminiscing of the day for my ignorance of the words “GOOD, SMART” on my progress report for performance, personality makes my veins light now. Being afraid of what these words really meant went home thinking of a cane. My parents gave me a sweet kiss on my cheek, made me breathe easy, but still at the end of the day left those words puzzling knowing me nothing more than that these can keep me miles away from a cane.

I did my schooling at Nellore Central School, India. The school stood promising in imparting their motto, Discipline, Devotion and Duty, to their children that stood them top in Central Board for Secondary Education schools in my place. It was greenery everywhere with huge bushes, big play ground, qualified staff members and being at a walkable distance from my home. My mother accompanied us, me and my brother, to the school and brought us lunch afternoon till we were grown enough for not being misplaced while on to school. A welcome difficulty of being a educating second child is to use the used textbooks, uniforms of the first one and I was no exception for it.