gpt4 book ai didi

c++ - 对象是在 setjmp 销毁之前创建的吗?

转载 作者:太空狗 更新时间:2023-10-29 20:14:30 26 4
gpt4 key购买 nike

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 << ") 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);
}
}

在这个例子中,析构函数被调用(如我所料),但这是标准行为吗?或者是编译器的扩展,还是简单的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 中实现协作线程。我想不出还有一次我用过它。并不是说没有任何用途,但它们非常罕见。

关于c++ - 对象是在 setjmp 销毁之前创建的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16272530/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com