views:

68

answers:

1

In the following code, what is the order in which the destructors of b, q and e are called, and which is called before handling the exception. (The "cout..." parts are leftover for the original question)

#include <iostream> 
using namespace std; 

class A { 
public: 
  A(int arg) : m(arg) { 
    cout << "A::A(int) " << m << endl; 
    m = 2*arg; 
  } 
  virtual void f() { 
    cout << "A::f() " << m << endl; 
  } 
  void g() { 
    cout << "A::g(A) " << m << endl; 
  } 

  int m; 
}; 

class B : public A { 
public: 
  B(int arg) : A(arg) { 
    cout << "B::B(int) " << m << endl; 
    m = 3*arg; 
  } 
  ~B() {
    cout << "B::~B()" << endl;
  } 
  void f() {
    cout << "B::f(A&) " << m << endl; 
  } 
  virtual void g() { 
    B q(*this);
    throw q; 
    cout << "B::g(A) " << m << endl; 
  } 
}; 

int main() { 
  try { 
    B b(1);
    b.g(); 
  } catch (A e) { 
    cout << "Error: "; 
    e.f(); 
  } 
  return 0; 
} 

If it's possible, could you explain the reason. Thank you.

+1  A: 

q's desctructor is called first because it is destroyed as the first part of stack unwinding (local objects in the inner most scope are destroyed first), then b's destructor is called, also as part of stack unwinding. Both are destroyed before the catch block is even entered. Stack unwinding happens before the exception handler is executed.

Bear in mind, though, that exception objects are copied so in B::g() a copy (the exception object) of q which is a copy of b is created and its lifetime extends to the end of the catch block. It is used to initialize (slicing!) e.

The destructor for the exception object itself (a copy of q) is executed immediately after e is destroyed (as the handler doesn't exit via a throw;). This ordering is specified in the standard.

Charles Bailey