C++ 是否在setjmp销毁之前创建对象?

C++ 是否在setjmp销毁之前创建对象?,c++,c++11,language-lawyer,setjmp,C++,C++11,Language Lawyer,Setjmp,在中,必须使用setjmp/longjmp来实现自定义错误处理 P>有很多资源,据说StjJMP/LangJMP不能很好地使用C++(例如,告诉他们与RAII一起使用的答案),但是回答说析构函数被调用。 我有一个例子(摘自并稍加修改): 它可以是未定义的行为,这取决于在执行相同的控制传输时是否会调用析构函数。在C++03中。参见第18.7节“其他运行时支持”,第4段: 函数签名longjmp(jmp_buf jbuf,int val)在本国际标准中具有更严格的行为。如果将控制转移到程序中的另一

在中,必须使用setjmp/longjmp来实现自定义错误处理

<> P>有很多资源,据说StjJMP/LangJMP不能很好地使用C++(例如,告诉他们与RAII一起使用的答案),但是回答说析构函数被调用。 我有一个例子(摘自并稍加修改):

它可以是未定义的行为,这取决于在执行相同的控制传输时是否会调用析构函数。在C++03中。参见第18.7节“其他运行时支持”,
第4段:

函数签名
longjmp(jmp_buf jbuf,int val)
在本国际标准中具有更严格的行为。如果将控制转移到程序中的另一个(目标)点的抛出异常会破坏任何自动对象,则在将控制转移到同一(目标)点的抛出点处调用
longjmp(jbuf,val)
具有未定义的行为

c++11中也有类似的语言:

函数签名
longjmp(jmp_buf jbuf,int val)
在本国际标准中具有更严格的行为。如果将
setjmp
longjmp
替换为
catch
throw
将调用任何自动对象的非平凡析构函数,则
setjmp/longjmp
调用对具有未定义的行为

然而,对于这段特定的代码,在转换过程中似乎没有调用析构函数,所以我相信它是安全的


现在,如果要更改代码以将创建移动到
setjmp
之后,这将成为未定义的行为。在我的设置(Debian下的gcc 4.4.5)中,以下代码(其他所有内容与您的问题相同):

输出结果:

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()
A()
a(0) called
A()
a(1) called
A()
a(2) called
A()
a(3) called
A()
~A()
您可以看到析构函数并没有作为跳转的一部分被调用,尽管由于未定义,它可能在某些系统上


底线是,您不应该从区域A跳到区域B,在区域B中,等效的
throw/catch
将正确地销毁对象,因为无法保证
longjmp
将调用析构函数

<>实际上,有人会说你根本不应该在C++中使用<代码> SETJMP/LangJMP <代码>,我自己也倾向于这样。即使在C语言中,我也很难看到这种需要


我想在我的整个职业生涯中(这是一个漫长的职业生涯)我曾经使用过它,在MS-DOS下用Turbo C实现协作线程。我想不出还有哪一次我用过它。并不是说没有任何用途,但它们将非常罕见。

但在这种情况下,没有自动对象会被异常破坏。是的,不会引发异常。@Bааћ,您的特定环境是否工作决不是UB的决定因素。有时UB的工作方式与您期望的完全一样,但它仍然是UB,并且在其他人的环境中(或者在蓝月期间,或者使用不同的编译器选项等等)的工作方式可能完全不同。对于明确的信息,标准始终是控制文档。我理解,如果UB在一个环境中工作,可能在另一个环境中不工作。顺便说一句,类型A的对象是在堆栈上创建的(请参见
main()
的第一行。不会引发异常。这些段落是否仍然相关?@Bццћ,不应该,至少作为跳转的一部分。当它超出范围时,它将在
main
的末尾被销毁。这在“正常”中有介绍处理本地/块范围的标准的一部分(C++03的3.3.2,C++11的3.3.3)。
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()