abort()
そのため、残念ながら特定のエラーを処理するために使用するライブラリ(私が作成したものではありません)があります。アプリケーション レベルでは、これらのエラーは回復可能であるため、ユーザーがクラッシュするのではなく、エラーを処理したいと考えています。したがって、次のようなコードを書くことになります。
static jmp_buf abort_buffer;
static void abort_handler(int) {
longjmp(abort_buffer, 1); // perhaps siglongjmp if available..
}
int function(int x, int y) {
struct sigaction new_sa;
struct sigaction old_sa;
sigemptyset(&new_sa.sa_mask);
new_sa.sa_handler = abort_handler;
sigaction(SIGABRT, &new_sa, &old_sa);
if(setjmp(abort_buffer)) {
sigaction(SIGABRT, &old_sa, 0);
return -1
}
// attempt to do some work here
int result = f(x, y); // may call abort!
sigaction(SIGABRT, &old_sa, 0);
return result;
}
非常にエレガントなコードではありません。このパターンはコードのいくつかの場所で繰り返さなければならないので、少し単純化し、再利用可能なオブジェクトにラップしたいと思います。私の最初の試みは、RAII を使用してシグナル ハンドラーのセットアップ/ティアダウンを処理することです (各関数で異なるエラー処理が必要なため、実行する必要があります)。だから私はこれを思いついた:
template <int N>
struct signal_guard {
signal_guard(void (*f)(int)) {
sigemptyset(&new_sa.sa_mask);
new_sa.sa_handler = f;
sigaction(N, &new_sa, &old_sa);
}
~signal_guard() {
sigaction(N, &old_sa, 0);
}
private:
struct sigaction new_sa;
struct sigaction old_sa;
};
static jmp_buf abort_buffer;
static void abort_handler(int) {
longjmp(abort_buffer, 1);
}
int function(int x, int y) {
signal_guard<SIGABRT> sig_guard(abort_handler);
if(setjmp(abort_buffer)) {
return -1;
}
return f(x, y);
}
確かに の体はこの方function
がはるかに単純で明快ですが、今朝、ある考えが浮かびました。これは動作することが保証されていますか? ここに私の考えがあります:
setjmp
/の呼び出し間で揮発性または変化する変数はありませんlongjmp
。- と
longjmp
同じスタック フレーム内の場所に移動し、setjmp
通常return
は ing を実行するため、関数の終了ポイントでコンパイラが出力したクリーンアップ コードをコードが実行できるようにしています。 - 期待どおりに動作するようです。
しかし、これは未定義の動作である可能性が高いと感じています。皆さんはどう思いますか?