我仍然不相信在没有“构造”的对象的情况下调用`析构函数`

时间:2011-11-13 11:20:15

标签: c++ visual-studio-2008

案例1

这是基于昨天发布的另一个question of mine,我接受了,尽管不情愿,可以通过以下代码进行总结:

{
    ...
    goto Label;
    A a;
    ...
    Label:DoSomething();
}

其中A是具有已定义constructor和默认destructor的任何类。 DoSomething()没有使用a。根据我的理解(我仍在努力使用C ++基本结构)A在这种情况下不会调用析构函数,因为对象a甚至没有被构造。

请注意,VS2008编译器会向您发出警告(C4533 : initialization of 'a' is skipped by 'goto Label')而不是错误,除非您尝试为destructor定义A,当编译器神秘地更改警告时陷入错误(C2362 : initialization of 'a' is skipped by 'goto Label'),好像阻止某人探究问题,顺便提一下,这让我想起了自然中的量子现象。

案例2

这是constructor抛出异常的正常现象,在这种情况下,destructor未被调用,如herehere所述。

因此

Case1 中,constructor未被调用,但调用destructor来销毁未创建的内容,这对我来说似乎很奇怪。在 Case2 中调用构造函数,抛出异常并且不调用destructor,这对我来说似乎是合理的。

我相信这两个例子值得进一步澄清。

修改

Case2 中,编译器可能使用标志来避免破坏因抛出而未构造的对象。为什么 Case1 中可以使用相同的标记来识别由于goto而未构造的对象?

2 个答案:

答案 0 :(得分:4)

在C ++中,为了这个原因,禁止跨变量初始化(构造函数调用):goto跳过构造函数调用。在goto和对DoSomething的调用之后,变量a将超出范围,因此析构函数将在a上调用,由于goto跳过构造函数调用,因此尚未构造析构函数。

VS2008在这里很宽松,当自动生成的析构函数(可能在POD上)没有效果时,允许违反标准。

答案 1 :(得分:3)

实际上案例1是无效的C ++。编译器必须为此发出诊断,并且根本不允许编译它。如果编译器无论如何编译它,它完全取决于编译器如何处理它。在这种情况下不破坏对象是明智的,但是这需要额外的机器,这意味着正确的程序需要不必要的开销(程序需要检查内部标志是否已经构造了对象)。我不认为在编译时总是可以解决是否需要进行检查,因为这可能等同于暂停问题。