加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c – 在setjmp被破坏之前是否创建了对象?

发布时间:2020-12-16 09:44:28 所属栏目:百科 来源:网络整理
导读:在 jpeglib中,必须使用setjmp / longjmp来实现自定义错误处理. 有很多资源据说setjmp / longjmp与c不兼容(例如this question中的答案告诉他们确实与RAII一起使用),但this question的答案表示析构函数被调用. 我有这个例子(取自here并稍作修改): #include io
在 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段:

The function signature longjmp(jmp_buf jbuf,int val) has more restricted behavior in this International Standard. If any automatic objects would be destroyed by a thrown exception transferring control to another (destination) point in the program,then a call to longjmp(jbuf,val) at the throw point that transfers control to the same (destination) point has undefined behavior.

c 11中有类似的语言:

The function signature longjmp(jmp_buf jbuf,int val) has more restricted behavior in this International Standard. A setjmp/longjmp call pair has undefined behavior if replacing the setjmp and longjmp by catch and throw would invoke any non-trivial destructors for any automatic objects.

但是,似乎没有为这段特殊代码调用转换的析构函数,所以我认为它是安全的.

现在,如果您要更改代码以将创建移动到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中的合作线程.我再也没有想过我曾经用过它.并不是说没有任何用途,但它们很少见.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读