Interix(SUA)默认情况下不调用析构函数,但在x86模式下有一个选项。
以test.cc
保存的测试程序如下:
#include <stdio.h>
#include <setjmp.h>
struct A {
~A() { puts("~A"); }
};
jmp_buf buf;
void f() {
A a;
longjmp(buf, 1);
}
int main() {
if (setjmp (buf))
return 0;
f();
}
以下是Interix的行为方式。为了简洁起见,我省略了PATH
的必要设置。
$ cc -mx86 test.cc && ./a.out
$ cc -mx86 -X /EHa test.cc && ./a.out
cl:命令行警告D9025:用'/EHa'覆盖'/EHs'
~A
$ cc -mamd64 test.cc && ./a.out
$ cc -mamd64 -X /EHa test.cc && ./a.out
cl:命令行警告D9025:用'/EHa'覆盖'/EHs'
$
评论表明cc -X /EHa
不符合POSIX标准,例如因为/EHa
会捕获信号。这并非完全正确:
$ cat test.cc
#include <signal.h>
int main() {
try {
raise(SIGFPE);
} catch (...) {
// ignore
}
}
$ cc -mx86 -X /EHa test.cc && ./a.out
cl:命令行警告D9025:用'/EHa'覆盖'/EHs'
Floating point exception (core dumped)
如果我将
raise(SIGFPE)
更改为除以零,我确实看到异常处理程序捕获它,但是POSIX和C++都不需要任何特定的行为,因此这不会影响符合性。也不是所有异步信号都被捕获:对于此程序:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
void sigint(int signal) {
puts("sigint");
exit(0);
}
int main() {
signal(SIGINT, sigint);
try {
for (;;) ;
} catch (...) {
}
}
“sigint” 在按下Ctrl-C后会被打印出来,正如预期的那样。我没有看到任何理由声称此实现不符合POSIX要求。
setjmp
/longjmp
,在此过程中如果需要调用非平凡析构函数会导致未定义行为。 - jxh