9

printfスタイルの書式設定に基づくロギング フレームワークがあります。

void Logger::debug(const char *fmt, ...) {
    va_list args;
    va_start(args, fmt);
    this->output(DebugLevel, fmt, args);
    va_end(args);
}

スローの場合、コンパイラはスタックを適切にアンワインドしますか、それともcatch 句にLogger::outputtry/catch ブロックを追加する必要がありますか? va_end(args)代わりにこれを RAII することはできますか、それともva_end魔法のようにできますか? 可能であれば、標準への参照を含めてください。

4

3 に答える 3

7

いいえ、できません。マクロだからできないという理由付けはばかげています。マクロは、コンストラクターおよびデストラクターから問題なく使用できます。ただし、同じ関数から呼び出す必要があるという特定の要件がありますva_startva_endそれらを別の関数に移動することは無効です。C++ は C 標準を指し、C 標準は「va_startおよびマクロの各呼び出しは、同じ関数内のva_copy対応するマクロの呼び出しと一致する必要がある」と述べています。va_end(7.15.1)va_endヘルパー クラスのデストラクタから呼び出すと、機能する場合と機能しない場合があります。標準の要件を満たしていないため、動作は未定義です。

編集: 他の質問に関しては、例外がスローされたときに必要ですか? 「マクロの呼び出し」は実際にはコードがそのマクロを呼び出すポイントに到達することを必要としないva_endという正当な議論を行うことができます(va_endマクロの呼び出しは厳密にはコンパイル時のみのアクションです) が、それが必要であることを強く示唆しています。はい、例外が発生する可能性がある場合はtry/を使用してください。catchC99 の理論的根拠は、メモリを割り当てる可能性がva_copyあるという説明の中で簡単に述べています。va_start(実際にそうする実装は知りません。)そのような実装でva_endは、そのメモリの割り当てを解除するため、スキップva_endするとメモリリークが発生します。

于 2012-07-25T08:35:45.063 に答える
0

はい、これは Boost.ScopeExit を使用して RAII できますが va_start/va_end はマクロです。

于 2012-07-25T08:19:08.560 に答える
0

いいえva_startva_endマクロです。RAIIしたがって、それらを編集することはできません。また、例外についても特別な注意は必要ありません。

于 2012-07-25T08:13:32.920 に答える