案例1
这是基于昨天发布的另一个我的问题,我不情愿地接受了这一消息,可以用以下代码进行总结:
{
...
goto Label;
A a;
...
Label:DoSomething();
}其中A是具有定义的constructor和默认destructor的任何类。DoSomething()不使用a。据我所知(我仍在努力处理C++基本构造),在这种情况下不会调用A的析构函数,因为对象a甚至没有构造。
请注意,VS2008编译器给出的警告(C4533 : initialization of 'a' is skipped by 'goto Label')不是错误,除非您试图为A定义一个destructor,当编译器神秘地将警告更改为错误(C2362 : initialization of 'a' is skipped by 'goto Label')时,似乎是为了阻止某人探究这个问题,顺便说一句,这让我想起了本质上的量子现象。
案例2
这是constructor抛出异常的正常情况,在这种情况下,不调用destructor,正如讨论的这里和这里。
因此
在Case1中,没有调用constructor,但是调用destructor是为了销毁未创建的东西,对我来说这似乎很奇怪。在Case2中,调用构造函数,抛出异常,不调用destructor,这在我看来是合理的。
我认为这两个例子值得进一步澄清。
编辑
在Case2中,编译器可能使用标志来避免破坏由于抛出而非构造的对象。为什么不能在Case1中使用这些相同的标志来标识由于goto而没有构造的对象?
发布于 2011-11-13 11:27:18
在C++中,跨越变量初始化(构造函数调用)的gotos正是因为这个原因而被禁止的: goto跳过构造函数调用。在goto和对DoSomething的调用之后,变量a将超出作用域,因此将在a上调用析构函数,因为goto跳过构造函数调用而没有构造析构函数。
VS2008在这里是宽容的,允许当自动生成的析构函数(可能在POD上)没有影响时违反标准。
发布于 2011-11-13 11:30:47
实际上,案例1是无效的C++。编译器必须为此发出诊断,并且允许根本不编译它。如果编译器无论如何都会编译它,那么它将完全取决于编译器如何处理它。在这种情况下,不销毁对象是明智的,但是这需要额外的机器,这意味着不需要为正确的程序设置开销(程序需要检查内部标志是否已经构造了该对象)。我不认为总是可以在编译时解决该检查是否需要,因为这很可能等同于停止问题。
https://stackoverflow.com/questions/8111163
复制相似问题