最近作成したプログラムで、「ビジネスロジック」コードがサードパーティまたはプロジェクトAPIで例外をトリガーしたときにログに記録したいと思いました。(明確にするために、APIの使用によって例外が発生したときにログに記録したいと思います。これは実際よりも何フレームも上throw
である可能性があり、実際よりも何フレームも下である可能性がありますcatch
(例外ペイロードのログが発生する可能性があります。))続く:
void former_function()
{
/* some code here */
try
{
/* some specific code that I know may throw, and want to log about */
}
catch( ... )
{
log( "an exception occurred when doing something with some other data" );
throw;
}
/* some code here */
}
つまり、例外が発生した場合は、catch-all句を作成し、エラーをログに記録して、再スローします。私の考えでは、これは安全です。有用な情報を取得するための例外への参照がまったくないため、一般的にキャッチオールは悪いと見なされます。ただし、再スローするだけなので、何も失われません。
さて、それ自体は問題ありませんでしたが、他のプログラマーがこのプログラムを変更し、上記に違反することになりました。具体的には、ある場合には大量のコードをtry-blockに入れ、別の場合には「throw」を削除して「return」を配置しました。
私の解決策はもろいものでした。それは将来の変更に耐えるものではありませんでした。
これらの問題がない、より良い解決策が欲しいです。
上記の問題がない別の解決策がありますが、他の人はそれをどう思っているのでしょうか。これはRAIIを使用します。具体的には、構築ではtrueでstd::uncaught_exception
ないが、破棄ではtrueである場合に暗黙的にトリガーする「スコープ出口」オブジェクトです。
#include <ciso646> // not, and
#include <exception> // uncaught_exception
class ExceptionTriggeredLog
{
private:
std::string const m_log_message;
bool const m_was_uncaught_exception;
public:
ExceptionTriggeredLog( std::string const& r_log_message )
: m_log_message( r_log_message ),
m_was_uncaught_exception( std::uncaught_exception() )
{
}
~ExceptionTriggeredLog()
{
if( not m_was_uncaught_exception
and std::uncaught_exception() )
{
try
{
log( m_log_message );
}
catch( ... )
{
// no exceptions can leave an destructor.
// especially when std::uncaught_exception is true.
}
}
}
};
void potential_function()
{
/* some code here */
{
ExceptionTriggeredLog exception_triggered_log( "an exception occurred when doing something with some other data" );
/* some specific code that I know may throw, and want to log about */
}
/* some code here */
}
私は知りたいです:
- 技術的には、これは堅牢に機能しますか?最初はうまくいくようですが、の使用に関していくつかの注意点があることを私は知ってい
std::uncaught_exception
ます。 - 私が望むことを達成する別の方法はありますか?
注:この質問を更新しました。具体的には、次のようになりました。
- 関数呼び出しの周りに、最初に欠落していた
try
/を追加しました。catch
log
std::uncaught_exception
建設中の状態の追跡を追加しました。これは、このオブジェクトが、例外スタックの巻き戻しの一部としてトリガーされる別のデストラクタの「try」ブロック内に作成される場合を防ぎます。- 新しい「potential_function」を修正して、以前のように一時オブジェクトではなく、名前付きオブジェクトを作成しました。