BЈо*_*вић 3 c++ language-lawyer longjmp c++11
在jpeglib中,必须使用setjmp/longjmp来实现自定义错误处理.
有很多资源据说setjmp/longjmp与c ++不兼容(例如这个问题中的答案告诉他们确实与RAII一起使用),但是这个问题的答案是说析构函数被调用了.
我有这个例子(取自这里并修改了一下):
#include <iostream>
#include <csetjmp>
std::jmp_buf jump_buffer;
struct A
{
A(){std::cout<<"A()"<<std::endl;}
~A(){std::cout<<"~A()"<<std::endl;}
};
void a(int count)
{
std::cout << "a(" << count << ") called\n";
std::longjmp(jump_buffer, count+1); // setjump() will return count+1
}
int main()
{
// is this object safely destroyed?
A obj;
int count = setjmp(jump_buffer);
if (count != 9) {
a(count);
}
}
Run Code Online (Sandbox Code Playgroud)
在这个例子中,析构函数被调用(如我所料),但它是标准行为吗?或者它是编译器的扩展,还是简单的UB?
输出:
A()
a(0) called
a(1) called
a(2) called
a(3) called
a(4) called
a(5) called
a(6) called
a(7) called
a(8) called
~A()
Run Code Online (Sandbox Code Playgroud)
它可以是未定义的行为,具体取决于是否将调用析构函数是执行相同控制转移的异常.在C++ 03中.从部分18.7 Other runtime support
,paragraph 4
:
功能签名
longjmp(jmp_buf jbuf, int val)
在本国际标准中具有更多限制行为.如果任何自动对象将被抛出异常转移控制转移到程序中的另一个(目标)点,那么longjmp(jbuf, val)
在将控制转移到同一(目标)点的抛出点的调用具有未定义的行为.
c ++ 11中有类似的语言:
功能签名
longjmp(jmp_buf jbuf, int val)
在本国际标准中具有更多限制行为.甲setjmp/longjmp
如果替换呼叫一对有未定义的行为setjmp
和longjmp
由catch
和throw
将调用任何自动对象的任何非平凡的析构函数.
但是,似乎没有为这段特殊代码调用转换的析构函数,所以我认为它是安全的.
现在,如果你要改变的代码创建移动之后的setjmp
,这是不确定的行为.在我的设置(Debian下的gcc 4.4.5)中,以下代码(其他一切与您的问题相同):
int main() {
int count = setjmp (jump_buffer);
A obj;
if (count != 4) a (count);
}
Run Code Online (Sandbox Code Playgroud)
结果输出:
A()
a(0) called
A()
a(1) called
A()
a(2) called
A()
a(3) called
A()
~A()
Run Code Online (Sandbox Code Playgroud)
你可以看到析构函数不是作为跳转的一部分被调用的,虽然未定义,它可能在某些系统上.
最重要的是,你不应该从区域A跳到区域B,其中等价物throw/catch
将正确地破坏对象,因为无法保证longjmp
将调用析构函数.
实际上,有些人会说你根本不应该setjmp/longjmp
在C++ 中使用,我倾向于自己这样倾斜.即使在C中,我也很难看到它的需要.
我想我在整个职业生涯中曾经使用过一次(这是一个漫长的职业生涯),在MS-DOS下实现Turbo C中的合作线程.我再也没有想过我曾经用过它.并不是说没有任何用途,但它们很少见.
归档时间: |
|
查看次数: |
262 次 |
最近记录: |