Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++ exception safety

Tags:

c++

exception

Exceptional C++ mentions the following code

template <class T> class Stack 
{
    public:
      Stack();
      ~Stack();

      /*...*/

    private:
       T*     v_;      // ptr to a memory area big
       size_t vsize_;  //  enough for 'vsize_' T's
       size_t vused_;  // # of T's actually in use
};



template<class T> 
Stack<T>::Stack()
        : v_(new T[10]),  // default allocation
          vsize_(10),
          vused_(0)       // nothing used yet
{ 
}

It says that If one of the T constructors threw, then any T objects that were fully constructed were properly destroyed and, finally, operator delete was automatically called to release the memory. That makes us leakproof.

My understanding was that if a constructor throws an exception, the application should cleanup any allocated resources. How is the above leakproof?

like image 416
koobi Avatar asked Aug 05 '11 00:08

koobi


2 Answers

Quoting the C++03 standard, §5.3.4/8:

A new-expression obtains storage for the object by calling an allocation function. If the new-expression terminates by throwing an exception, it may release storage by calling a deallocation function. If the allocated type is a non-array type, the allocation function’s name is operator new and the deallocation function’s name is operator delete. If the allocated type is an array type, the allocation function’s name is operator new[] and the deallocation function’s name is operator delete[].

§5.3.4/17:

If any part of the object initialization described above terminates by throwing an exception and a suitable deallocation function can be found, the deallocation function is called to free the memory in which the object was being constructed, after which the exception continues to propagate in the context of the new-expression.

Consequently, if any T constructor throws an exception, the runtime will destroy any already-created subobjects of the T instance whose constructor threw, then call operator delete[] on the array as a whole, destroying any already-created elements and deallocating the array's memory.

like image 92
ildjarn Avatar answered Nov 15 '22 19:11

ildjarn


[Correction:] It is not. An exception in your constructor won't leak resources because the only place an exception could occur is inside the new expression, and if a new expression fails, the resources that were allocated by it are freed. Your situation is special because you only make one single allocation in the constructor -- in general this is not safe!

Your quoted phrase refers to is the delete operator for the failed-object whose constructor threw:

struct T
{
  T() { throw 1; }
  char data[200];
};

// in your code:

T * pt = new T;

In the last line, memory is allocated before the constructor is invoked. That memory is released in the event of an exception, by an automatic call to ::operator delete(pt). (In general, the matching delete-operator (not "expression"!) matching the new expression is called.)

It goes like this:

  • Successful construction: 1. Allocation. 2. Construction. 3. Destruction. 4. Deallocation.

  • Unsuccessful construction: 1. Allocation. 2. Deallocation.

Note that we only have an object after the constructor has completed -- so in the event of an exception in the constructor, we do not even have an object. That's why I said "failed-object" above with a hyphen, because it's not an object at all (like the Douglas-fir isn't a fir at all).

Your code is potentially entirely leak unsafe, if you are making more than one allocation which could throw - i.e. a leak occurs whenever one object has been successfully constructed but another, subsequent one fails. You should probably just not call new in the initializer list and instead put it in the body:

class Danger
{
  T * pt1, * pt2;
public:
  Danger()
  {
    try { pt1 = new T; } catch(...) { throw(); }
    try { pt2 = new T; } catch(...) { delete pt1; throw(); }
  }
};

Or, by the principle of single responsibility, don't use raw pointers but use resource managing containers that clean up after themselves!!

like image 29
Kerrek SB Avatar answered Nov 15 '22 21:11

Kerrek SB