1

例外をスローするたびに使用されるカスタム エラー クラスがあります。

class AFX_CLASS_EXPORT CCLAError : public CObject

次のコピー コンストラクターが定義されています。

CCLAError(const CCLAError& src) { AssignCopy(&src); } // (AssignCopy is a custom function)

これは、MSVC6 (Visual Studio 2003) で作成およびコンパイル/リンクされたものです。MSVC8 + (VS 2008 +) に対してコンパイルおよびリンクするために必要な変更を行っているところです。

msvc8 リンカーが呼び出されると、次のエラーが発生します。

LNK2001: unresolved external symbol "private: __thiscall CObject::CObject(class CObject const &)" (??0CObject@@AAE@ABV0@@Z)

エラーが私に伝えていることを理解しています.CObjectの子に対してコピーコンストラクターが定義されていないため、コピーコンストラクターが定義されていないため、CObjectに到達するまで継承ツリーを上ります。

を定義して最初にスローするライブラリをコンパイルするときに最初にエラーを見たのでCCLAError、それが原因であるかのように処理を進めています。

変更することでエラーを解決できました

throw CCLAError( ... )

throw new CCLAError( ... )

catch(CCLAError& e)
{
   throw e;
}

catch(CCLAError& e)
{
   throw;
}

ただし、キャッチされた例外を再スローするとコピー コンストラクターが呼び出される理由がわかりません。完全に明らかな何かが欠けていますか?その後、キャッチされた例外への参照を保持する変数を削除すると、コピー コンストラクターが呼び出されなくなるのはなぜですか?

4

6 に答える 6

10

式がその引数のコピーを作成する可能性があるため、スローされるオブジェクトの型はコピー可能でなければなりませんthrow(コピーは省略されるか、C++11 では代わりに移動が行われる可能性がありますが、コピー コンストラクターは引き続きアクセス可能で呼び出し可能でなければなりません)。

を使用して例外を再スローしてthrow;も、コピーは作成されません。を使用してキャッチされた例外オブジェクトをスローthrow e;すると、のコピーがe作成されます。これは、例外を再スローすることと同じではありません。

「更新された」コードが期待どおりに機能しません。 は、 によってスローされる例外catch (CCLAError&)のタイプであるタイプ の例外をキャッチしません。をキャッチする必要があります。ただし、これは行わないでください。値で例外をスローし、参照でキャッチします。すべての例外タイプはコピー可能である必要があります。CCLAError*throw new CCLAError(...);CCLAError*

于 2012-06-01T18:29:48.197 に答える
5

ただし、キャッチされた例外を再スローするとコピー コンストラクターが呼び出される理由がわかりません。

そうではありませんが、スローされた例外の再スローはthrow;. throw e;そうするとき、キャッチされた例外のコピーをスローするように要求しています。

于 2012-06-01T18:30:07.260 に答える
3

いくつかのポイント:

throw new foo()第一に、使用を呼び出さないでくださいthrow foo

あなたの書き込みの2番目:

catch(foo const &e) {
   throw e;
}

実際に新しい例外を作成します。たとえば、スローされた例外がfoo私の呼び出しのサブクラスである場合、throw eこの情報を失い、実際にコピー コンストラクターを使用fooして e から生成します。

今あなたが電話するとき

catch(foo const &e) {
   throw;
}

新しい例外を作成するのではなく、同じ例外を伝播します。

したがって、例外を前方に伝播するために使用しないでください。throw e;throw;

于 2012-06-01T18:31:34.170 に答える
1

例外をスローすると、通常、スローしているオブジェクトはスタックに常駐します。スタックは、スローのプロセスの一部としてクリーンアップされるため、コンパイラは、その時点を超えて存続できるコピーを作成する必要があります。

でオブジェクトをスローするとnew、実際のオブジェクトはスローされませんが、オブジェクトへのポインターがスローされます。つまり、catchブロックは参照ではなくポインターもキャッチする必要があります。ポインターを忘れないでください。そうしないとdelete、メモリ リークが発生します。

catch ブロックがthrow;代わりに使用する場合、throw e;以前に作成したコピーを再利用でき、別のコピーを作成する必要はありません。

于 2012-06-01T18:37:15.670 に答える
0

再スローの意味を誤解しているようです。あなたがするとき -

catch(CCLAError& e)
{
   throw e;
}

-- あなたは再スローしていません。代わりに、ご覧のとおり、実際に新しい例外のコピーを作成しています。代わりに (繰り返しますが、ご自分で見つけたように)、これが技術的に正しい再スロー方法です。

catch(CCLAError& e)
{
   throw;
}

Stroustrup の TC++PL の第 14 章を読んでください (14.3.1 は再スローを扱います)。

また、する必要はありません-

throw new CCLAError( ... )

代わりに、してください -

throw CCLAError( ... )

-- 以前と同じように、 CONST参照によってのみ受信します (一時的な参照を保持することはできません)。

catch(const CCLAError &e)
于 2012-06-01T18:38:20.790 に答える
-1

言語仕様により、コンパイラは元のオブジェクトのコピーを必要なだけ作成できます。コピー数に制限はありません。

つまり、カスタム例外クラスには、アクセス可能なコピー コンストラクター (コンパイラーが生成したもの、またはユーザー定義のもの) が必要です。

于 2012-06-01T18:30:11.537 に答える