先ほどの続き。
Egtra さんの指摘で、x86 でも /EH オプションが有効の場合には setjmp/longjmp でデストラクタが起動することが分かりました。
状況を確認してみましょう。まず、下記のクラスを用意して ctor/dtor の呼び出し状況がコンソールから分かるようにします。
struct Test { Test(int val):num(val) { std::cout << "ctor (" << num << ")" << std::endl; } ~Test() { std::cout << "dtor (" << num << ")" << std::endl; } int num; };
次いで下記のコードで setjmp/longjmp におけるデストラクタの動作状況を確認します。
jmp_buf gEnv; void ok() { Test aTest1(1); if (setjmp(gEnv) != 0) { return; } Test aTest2(2); longjmp(gEnv, 1); } int main() { ok(); return 0; }
これらを x86 コンパイラと x64 コンパイラで下記のようにコンパイルします。
cl.exe test_jmp.cpp /EHsc
実行すると x86 では下記のように表示されます。
ctor (1) ctor (2) dtor (2) dtor (1)
これは OK。
次いで、x64 では下記のように表示されます。
ctor (1) ctor (2) dtor (1)
あれれ?何かおかしい。ctor と dtor が対応づいていない。
さらにすんごく気になるケースがあったので追試。コード全体は下記のとおり。
#include <setjmp.h> #include <iostream> struct Test { Test(int val):num(val) { std::cout << "ctor (" << num << ")" << std::endl; } ~Test() { std::cout << "dtor (" << num << ")" << std::endl; } int num; }; jmp_buf gEnv; void ok() { Test aTest1(1); if (setjmp(gEnv) != 0) { return; } Test aTest2(2); longjmp(gEnv, 1); } void ng() { { Test aTest1(1); if (setjmp(gEnv) != 0) { return; } } Test aTest2(2); longjmp(gEnv, 1); } int main() { std::cout << "case 1 started." << std::endl; ok(); std::cout << "case 1 finished." << std::endl; std::cout << "case 2 started." << std::endl; ng(); std::cout << "case 2 finished." << std::endl; return 0; }
x86 の実行結果は下記のとおり…、なのですが最後にプログラムが落ちました。
case 1 started. ctor (1) ctor (2) dtor (2) dtor (1) case 1 finished. case 2 started. ctor (1) dtor (1) ctor (2) dtor (2)
x64 の実行結果は下記のとおりで、やはり ctor と dtor が対応づいていないようです。
case 1 started. ctor (1) ctor (2) dtor (1) case 1 finished. case 2 started. ctor (1) dtor (1) ctor (2) dtor (1) case 2 finished.
んー。やはりコンパイラのサポートがあるからといって、setjmp/longjmp と RAII の組み合わせは鬼門なのかな。