1. ホーム
  2. c++

[解決済み] C++ Exceptions 元の例外の再スローに関する質問

2022-07-25 20:03:05

質問

キャッチ内の次のappend()は、append()が呼ばれた効果を見るためにrethrown例外を引き起こすのでしょうか?

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?
}

どのように解決するのですか?

どちらの場合も、参照捕捉を行うため、元の例外オブジェクトの状態を効果的に変更することになります (元の例外オブジェクトは、以下の場所にあると考えることができます。 に存在すると考えることができます)。 -- 0x98e7058 のように)。 しかし

  1. で再スローしているので、最初のケースでは throw; (これは throw err; とは異なり、元の例外オブジェクトを、あなたの変更を加えて、quot;魔法の場所" で保持します。 0x98e7058 ) 意志 は append() の呼び出しを反映します。
  2. 2番目のケースでは、明示的に何かを投げるので をコピーします。 err が作成され、新たに投げられる(別のquot;魔法の場所" 0x98e70b0 -- というのは、コンパイラが知っている限りでは err のように、スタック上のオブジェクトが巻き戻されるかもしれないからです。 e0xbfbce430 にあるのではなく、quot;magical location" にある。 0x98e7058 である)ので を使用すると、派生クラス固有のデータが失われます。 を失うことになります。

何が起こっているのかを説明するための簡単なプログラムです。

#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

も参照してください。