質問
dynamic_castエラー処理に関連する良いプラクティスはありますか(必要のないときに使用しないことを除く)? NULLとbad_castがスローされる可能性があるので、どうすればよいのでしょうか。 両方をチェックする必要がありますか?そして、bad_castをキャッチするか、NULLを検出すると、おそらくとにかく回復できません... 今のところ、私はassertを使用して、dynamic_castがNULL値ではないかどうかを確認しています。コードレビューでこのソリューションを受け入れますか?
解決
dynamic_cast
する必要があるが成功した場合、代わりにboost::polymorphic_downcast
を使用することをお勧めします。これは次のようになります。
assert(dynamic_cast<T*>(o) == static_cast<T*>(o));
return static_cast<T*>(o);
これにより、デバッグビルドでエラーを検出すると同時に、リリースビルドでのランタイムオーバーヘッドを回避できます。
キャスト might が失敗する可能性があり、それを検出する場合は、bad_cast
を使用して参照型にキャストします。このキャストは、エラーの場合にif
をスローし、プログラムを停止します。 (これは、あなたが言うように、とにかく回復しない場合に適しています)
T& t = dynamic_cast<T&>(o);
t.func(); //< Use t here, no extra check required
コンテキストで0ポインタが意味をなす場合にのみ、ポインタ型にassert
を使用します。次のような<=>で使用することもできます。
if (T* t = dynamic_cast<T*>(o)) {
t->func(); //< Use t here, it is valid
}
// consider having an else-clause
この最後のオプションでは、<=>が0を返す場合に実行パスが意味をなすことを確認する必要があります。
あなたの質問に直接答えるには、コードに明示的な<=>を含めることに対して、私が与えた最初の2つの選択肢のうちの1つを選びます:)
他のヒント
bad_castは、参照をキャストするときにのみスローされます
dynamic_cast< Derived & >(baseclass)
ポインターをキャストするとNULLが返されます
dynamic_cast< Derived * >(&baseclass)
したがって、両方をチェックする必要はありません。
アサートは受け入れられますが、それはコンテキストに大きく依存します。それから、ほとんどすべてのアサートに当てはまります...
はい、いいえ。
boost::polymorphic_downcast<>
は、デバッグフェーズ中にdynamic_cast<>
のエラーを処理するのに適したオプションです。ただし、polymorphic_downcast<>
は、コンパイル時に渡されるポリモーフィック型を予測できる場合にのみを使用する必要があることに注意してください、そうでない場合は<=>を代わりに使用する必要があります。
ただし、次のシーケンス:
if (T1* t1 = dynamic_cast<T1*>(o))
{ }
if (T2* t2 = dynamic_cast<T2*>(o))
{ }
if (T3* t3 = dynamic_cast<T3*>(o))
{ }
は、ポリモーフィズムおよび仮想関数によって解決されるべき非常に悪いデザインを示します。
依存します...;-)
dynamic_cast
が何か有用なものを与えると本当に期待していた場合、たとえば、私と他の誰も基本クラスへのポインターのコンテナにポリモーフィック型を追加しなかった場合、参照キャストを行い、 std::bad_cast
アプリケーションを強制終了します-他にやることはほとんどないでしょう。
ただし、必ずしも実装する必要のないインターフェイスによって公開される機能についてポリモーフィック型を照会する場合、ポインターキャストを使用すると、NULLはエラーになりません(もちろん、私はその場に本当に存在する能力を期待していなかったが、そもそも参照キャストに行っていた...)
「依存する」という答えに同意し、<!> quot;優雅な劣化<!> quot;を追加します:キャストがどこかで失敗するだけでは、アプリケーションが失敗するのに十分な理由ではありませんユーザーは仕事を失うなど)。アサートと防御プログラミングの組み合わせをお勧めします:
ptr = dynamic_cast<MyClass>(obj);
ASSERT(ptr);
if(ptr)
{
// do stuff
}