c – 在setjmp被破坏之前是否创建了对象?
在
jpeglib中,必须使用setjmp / longjmp来实现自定义错误处理.
有很多资源据说setjmp / longjmp与c不兼容(例如this question中的答案告诉他们确实与RAII一起使用),但this question的答案表示析构函数被调用. 我有这个例子(取自here并稍作修改): #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 << ") calledn"; 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); } } 在这个例子中,析构函数被调用(如我所料),但它是标准行为吗?或者它是编译器的扩展,还是简单的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() 解决方法
它可以是未定义的行为,具体取决于是否将调用析构函数是执行相同控制转移的异常.在C 03中.从第18.7节其他运行时支持,第4段:
c 11中有类似的语言:
但是,似乎没有为这段特殊代码调用转换的析构函数,所以我认为它是安全的. 现在,如果您要更改代码以将创建移动到setjmp之后,那么这将成为未定义的行为.在我的设置(Debian下的gcc 4.4.5)中,以下代码(其他所有内容与您的问题相同): int main() { int count = setjmp (jump_buffer); A obj; if (count != 4) a (count); } 结果输出: A() a(0) called A() a(1) called A() a(2) called A() a(3) called A() ~A() 你可以看到析构函数不是作为跳转的一部分被调用的,虽然未定义,它可能在某些系统上. 最重要的是,您不应该从区域A跳到区域B,其中等效的throw / catch会正确地破坏对象,因为不能保证longjmp会调用析构函数. 实际上,有些人会说你根本不应该在C中使用setjmp / longjmp,而且我倾向于自己这样倾斜.即使在C中,我也很难看到它的需要. 我想我在整个职业生涯中曾经使用过一次(这是一个漫长的职业生涯),在MS-DOS下实现Turbo C中的合作线程.我再也没有想过我曾经用过它.并不是说没有任何用途,但它们很少见. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |