129

キャッチ内の次の append() により、再スローされた例外が呼び出された append() の効果を確認できますか?

try {
  mayThrowMyErr();
} catch (myErr &err) {
  err.append("Add to my message here");
  throw; // Does the rethrow exception reflect the call to append()?
}

同様に、このように書き直すと、実際の例外が 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?
}
4

4 に答える 4

166

どちらの場合も、参照によってキャッチするため、元の例外オブジェクトの状態を効果的に変更しています (これは、次の巻き戻し中に有効なままになる魔法のメモリ位置にあると考えることができます。以下の0x98e7058例を参照してください)。でも、

  1. 最初のケースでは、 で再スローするためthrow;( とは異なりthrow err;、元の例外オブジェクトを変更して保持し、前述の「魔法の場所」で0x98e7058)に append() の呼び出しが反映されます。
  2. 2 番目のケースでは、何かを明示的にスローするため、 のコピー作成errされ、(別の「魔法の場所」で) 新たにスローされます。 )の「魔法の場所」ではなく、そのため、基本クラス インスタンスのコピー構築中に派生クラス固有のデータが失われます。0x98e70b0erre0xbfbce4300x98e7058

何が起こっているかを説明する簡単なプログラム:

#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;
}

結果:

  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

以下も参照してください。

于 2010-03-02T03:12:29.510 に答える
9

はい、再スローすると、参照によって変更された元の例外オブジェクトが再スローされます。また、基本クラスの参照をキャッチして変更し、元の派生例外タイプをthrow;.

于 2010-03-02T03:07:20.383 に答える
1

最初の質問は、はい。

しかし、第二に、ヴラドの答えを参照してください。コピー ctor を処理するには、例外オブジェクトを慎重に設計する必要があります。慣例により、基本クラスはその子を認識しないため、派生クラスによって保持される追加データが失われる可能性が高くなります。

于 2010-03-02T03:09:06.533 に答える