C++ Exceptions questions on rethrow of original exception

c++, exception, rethrow

Solution

In both cases, since you catch by reference, you are effectively altering the state of the original exception object (which you can think of as residing in a magical memory location which will stay valid during the subsequent unwinding -- `0x98e7058` in the example below). However,

- In the first case, since you rethrow with `throw;` (which, unlike `throw err;`, preserves the original exception object, with your modifications, in said "magical location" at `0x98e7058`) will reflect the call to append()

- In the second case, since you throw something explicitly, a copy of `err` will be created then thrown anew (at a different "magical location" `0x98e70b0` -- because for all the compiler knows `err` could be an object on the stack about to be unwinded, like `e` was at `0xbfbce430`, not in the "magical location" at `0x98e7058`), so you will lose derived-class-specific data during the copy-construction of a base class instance.

Simple program to illustrate what's happening:

#include <stdio.h>

struct MyErr {
  MyErr() {
    printf("  Base default constructor, this=%p\n", this);
  }
  MyErr(const MyErr& other) {
    printf("  Base copy-constructor, this=%p from that=%p\n", this, &other);
  }
  virtual ~MyErr() {
    printf("  Base destructor, this=%p\n", this);
  }
};

struct MyErrDerived : public MyErr {
  MyErrDerived() {
    printf("  Derived default constructor, this=%p\n", this);
  }
  MyErrDerived(const MyErrDerived& other) {
    printf("  Derived copy-constructor, this=%p from that=%p\n", this, &other);
  }
  virtual ~MyErrDerived() {
    printf("  Derived destructor, this=%p\n", this);
  }
};

int main() {
  try {
    try {
      MyErrDerived e;
      throw e;
    } catch (MyErr& err) {
      printf("A Inner catch, &err=%p\n", &err);
      throw;
    }
  } catch (MyErr& err) {
    printf("A Outer catch, &err=%p\n", &err);
  }
  printf("---\n");
  try {
    try {
      MyErrDerived e;
      throw e;
    } catch (MyErr& err) {
      printf("B Inner catch, &err=%p\n", &err);
      throw err;
    }
  } catch (MyErr& err) {
    printf("B Outer catch, &err=%p\n", &err);
  }
  return 0;
}

Result:

  Base default constructor, this=0xbfbce430
  Derived default constructor, this=0xbfbce430
  Base default constructor, this=0x98e7058
  Derived copy-constructor, this=0x98e7058 from that=0xbfbce430
  Derived destructor, this=0xbfbce430
  Base destructor, this=0xbfbce430
A Inner catch, &err=0x98e7058
A Outer catch, &err=0x98e7058
  Derived destructor, this=0x98e7058
  Base destructor, this=0x98e7058
---
  Base default constructor, this=0xbfbce430
  Derived default constructor, this=0xbfbce430
  Base default constructor, this=0x98e7058
  Derived copy-constructor, this=0x98e7058 from that=0xbfbce430
  Derived destructor, this=0xbfbce430
  Base destructor, this=0xbfbce430
B Inner catch, &err=0x98e7058
  Base copy-constructor, this=0x98e70b0 from that=0x98e7058
  Derived destructor, this=0x98e7058
  Base destructor, this=0x98e7058
B Outer catch, &err=0x98e70b0
  Base destructor, this=0x98e70b0

Also see:

- Scope of exception object in C++

- Throwing ... "by reference"

Problem

Will the following append() in the catch cause the rethrown exception to see the effect of append() being called? ``` try { mayThrowMyErr(); } catch (myErr &err) { err.append("Add to my message here"); throw; // Does the rethrow exception reflect the call to append()? } ``` Similarly, if I rewrite it this way, will bit slicing occur if the actual exception is derived by myErr? ``` try { mayThrowObjectDerivedFromMyErr(); } catch (myErr &err) { err.append("Add to my message's base class here"); throw err; // Do I lose the derived class exception and only get myErr? } ```

Original source

Related problems