Monday, June 13, 2011
My Website
I launched my personal website, website link, detailing my academic and research projects I am involved in so far. Though it's a naive website but lot of hard work went into the projects that it displays. Hope you guys like it :)
Thursday, April 14, 2011
Can an array be considered as a pointer ?
Similarities in the way of accessing between arrays and pointers in C/C++ make many programming beginners to conclude - " Arrays are (kind of) Pointers ! ". Possibility of accessing array elements much like pointers is a too easy slip to believe so. But in reality, they are entirely different.
Mythical reasons
Reason 1:
Operator * is the first culprit. Elements of the array can also be accessed much like dereferencing a pointer. Let's work on with an example -
void foo() { int lVariable = 10 ; int *lPtr = &(lVariable); int lArray[] = {1,2,3,4,5} ; std::cout <<*(lPtr) << "\n" ; // Dereferencing the pointer to get the value at the // pointer pointed location. for( int i=0; i<5; ++i ) std::cout <<*(lArray+i) << "\n" ; // Notice dereferencing an array element much // like a pointer. }
When an 1D array is passed to (or) returned by a function, it decays to a pointer pointing to the first element of the array. So, " Array is a kind of Pointer ! ".
void foo( int *decayPtr ) { // Access array elements either by operator [] (or) * } // Function foo can also be defined differing it's argument semantics as - // i) void foo( int decayPtr[5] ) { } // ii) void foo( int decayPtr[] ) { } // Either way defined will make the compiler convert to pointer type and the size mentioned in the array // index is just ignored by the compiler. int main() { int lArray[] = {1,2,3,4,5} ; foo(lArray) ; }The above two situations are compelling enough to conclude either arrays are (a kind of) pointers. No they are not !! Arrays and pointers are no way related.
Reducito ad absurdum
Sometimes it is tough to prove the claim and the process of reverse engineering eases the job. For time being, assume array is (kind of) pointer. If array is a pointer then much like any other raw pointer it can be assigned an address location.
void foo() { int lVariable = 10 ; int lArray[] = {1,2,3,4,5} ; lArray = &(lVariable) ; // If array is a pointer of any kind, assignment operation // should be valid. } Error: Incompatible types in assignment of 'int*' to 'int[5]'The error message is crystal clear enough to say it all and dispel the belief. How ever, when you pass the array to a function it is entirely a different story. The function's argument is pointer itself and so can either point to a different location at the cost loosing the access to array elements if the initial pointer's content is not stored in a temporary variable.
void foo( int *decayPtr ) { int lVariable = 10 ; decayPtr = &(lVariable) ; // Perfectly valid because decayPtr is not an array. // After assignment, it lost the starting address of array element it // had initially and noway can be retained back if not stored in a // temporary pointer variable. }
Conclusion
Array is just contiguous memory location(s) that can hold similar data types. It's size cannot be modified once allocated. Pointer variable of type "T" can hold the address of variable of type "T". They are just what they are and not even distant cousins.
PS:
- The word "decay" is a loosely used term to understand for convenience when array is passed or returned.
- As always, the disclaimer holds good for this post too :)
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.
- What if an exception rise in the complex part of the code ?
- What if there is an early return in the complex part of the code ?
- What if you accidentally placed another delete statement on rawPtr ?
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 scopeWhat 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 scopeThe 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 releasedreset
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 scope2. 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
class foo { int* ptr; int var; public: foo() { var = 10; ptr = new int; *ptr = var; } ~foo() { delete ptr; } };
- It's using constructor to initialize it's member variables.
- 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;
- Copy Constructor
- Copy Assignment Operator
- Destructor
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; } };
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 "
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.