Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Exception Handling in the C++ Constructor

3,190 views

Published on

A discussion on the exception handling in the constructor of C++

Published in: Technology, Business
  • That code is ugly, and not even correct. Why are you calling delete str1 when str1 never got initialized? That will try to delete a garbage pointer. Same problem for delete str2 . Also, because you swallow the exceptions when the constructor exits both pointers will be left containing garbage values.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Be the first to like this

Exception Handling in the C++ Constructor

  1. 1. SOM-ITSOLUTIONS C++ Exception Handling at C++ Constructor SOMENATH MUKHOPADHYAY som-itsolutions #A2 1/13 South Purbachal Hospital Road Kolkata 700078 Mob: +91 9748185282 Email: ​som@som-itsolutions.com​ / ​som.mukhopadhyay@gmail.com Website:​ ​http://www.som-itsolutions.com/ Blog: ​www.som-itsolutions.blogspot.com
  2. 2. Its a very common problem in C++ that if a class's constructor throws an exception (say memory allocation exception) how we should handle it. Think about the following piece of code. CASE I: class A{ private: int i; //if exception is thrown in the constructor of A, i will de destroyed by stack unwinding //and the thrown exception will be caught A() { i = 10; throw MyException(“Exception thrown in constructor of A()”); } }; void main(){ try{ A(); } catch(MyException& e){ e.printerrmsg(); } } Here class A's constructor has thrown an exception.. so the best way to handle such situation is to instantiate A inside a try block...if exception is thrown in the constructor of A, i will be destroyed by stack unwinding and the thrown exception will be caught... try​catch block in exception is very important as constructor cannot return anything to indicate to the caller that something wrong has happened... CASE II Lets consider the following case. class A{ private: char* str1; char* str2; A() { str1 = new char[100]; str2 = new char[100]; } }
  3. 3. Here in class A we have two dynamically allocated char array. Now suppose while constructing A, the system was able to successfully construct the first char array, i.e. str1. However, while allocating the memory of str2, it throws OutOfMemory exception. As we know the destructor of an object will be called only if the object is fully constructed. But in this case the object is not fully constructed. Hence even if we release the memory in the destructor of A, it will never be called in this case. So what we will have is that the stack based pointers, i.e. str1 and str2 will be deleted because of stack unwinding. If you can’t understand the previous line, here is what happened when we allocate a memory in heap. Look at the following diagram. This is what happened when we write ​char* ptr = new char[100]; It means that the ptr itself is on the stack while the memory that it is pointing to is in the heap. So the memory that have been allocated in the Heap won’t be destroyed. Hence we will have two blocks of heap memory ( one for the str1 that is 100 bytes long and the other for whatever have been allocated by str2 before the exception being thrown) which are not referenced by any pointer (str1 and str2 which have already been destroyed by the stack unwinding). Hence it is a case of memory leak. Now the question is how can we handle the above situation. We can do it as follows. class A{ private: char* str1; char* str2; A() { try{
  4. 4. str1 = new char[100]; } catch (...){ delete[] str1; throw(); //rethrow exception } try{ str2 = new char[100]; } catch(...){ delete[] str1; delete[] str2; throw(); //rethrow exception } But the best way to handle this kind of situation in modern C++ is to use auto_ptr/shared_ptr. Look at the following piece of code to know how we have used boost’s shared pointer to avoid memory leaks in the C++ constructor. #include <iostream> #include <string> #include <memory> #include <boost/shared_ptr.hpp> #include <boost/shared_array.hpp> using namespace std; class SomeClass{ public: SomeClass(){} ~SomeClass(){}; }; typedef boost::shared_ptr<SomeClass> pSomeClass; typedef boost::shared_ptr<cha> pChar; typedef boost::shared_array<char> pBuffer; class MyException{ public: MyException(string str){ msg = str; } void printerrmsg(){ cout<<msg.c_str<<endl; }
  5. 5. private: string msg; }; class A{ private: int i; pChar m_ptrChar; pSomeClass m_ptrSomeClass; pBuffer m_pCharBuffer; public: A():m_ptrChar(new char),m_ptrSomeClass(new SomeClass),m_pCharBuffer(new char[100]) { i = 10; throw MyException("Exception at A's constructor"); } }; In Symbian C++, it is handled by a concept called two phase constructor... (it came into the picture because there was no template concept in earlier Symbian C++, and hence there was no auto_ptr)... in this process, if we want to create a dynamic memory allocation at the heap pointed by say *pMem, then in the first phase of construction we initialize the object pointed by pMem;. obviously this cannot throw exception... We then push this pMem to the cleanup stack... and in the second phase of construction, we allocate memory pointed by pMem... so, if the constructor fails while allocating memory, we still have a reference of pMem in the cleanup stack... we just need to pop it and destroy it... hence there is no chance of memory leak...
  6. 6. EXCEPTION CLASS #include <iostream> #include <string> #include <memory> class MyException(string str){ private: string msg; public: MyException(string str){ msg = str; } void printerrmsg(){ cout<<msg.c_str()<<endl; } }

×