1

在我研究异常机制的过程中,我发现在堆栈展开时会调用对象字段的析构函数。让我明确解释一下:

class X
{
  File_ptr aa;
  Lock_ptr bb;
public:
 X(const char* x,const char* y):aa(x),bb(y){}
//.......
}

所以,现在如果 Lock_ptr 的构造函数抛出异常,对象aa将被销毁;问题是“为什么”?我一直认为对象的文件不是通常的自动(本地)对象。它们是在构造函数初始化它们之前创建的。所以它们超出构造函数的范围后不能被销毁(否则它们会被销毁)构造函数完成了它的工作)

4

3 回答 3

5

子对象(包括非静态数据成员)与它们所属的完整对象具有相同的存储期限。这与说它们是自动的不同。自动对象在块结束时被销毁。每当其完整对象被销毁时,子对象就会被销毁。例如,如果完整的对象是用创建new和销毁的delete(即具有动态存储持续时间),那么子对象也会在对 的调用中创建new,并在对 的调用中销毁delete。另一方面,自动对象的子对象也是自动的。

如果 for 的构造函数X::bb抛出异常,则表示X无法构造该类型的完整对象。所有已经构造的子对象,例如X::aa,都必须销毁,因为一个子对象,与它的完整对象具有相同的存储时间,没有完整的对象就无法生存。

另一方面,如果整个X对象的构造成功完成,X::aa并且其他子对象将不会被销毁,直到(不久之后)整个X对象被销毁。

C++ 的构造和销毁规则旨在保证,只要程序正常终止,所创建的每个对象也只会被销毁一次。这对于 RAII 习语来说是必不可少的。在这个例子中,如果X::aa在构建时获取资源,语言必须确保这些资源会被释放。如果X::aa构造失败时没有调用 ' 的析构函数X,那么应该什么时候调用呢?

于 2014-06-27T17:54:33.137 回答
3

aaX 有一个构造and的“真实”构造函数bb,然后调用 X 的构造函数体。这就是为什么初始化列表在X构造函数“body”之前的原因。在这个“真正的”构造函数中,基类和成员的创建就好像它们按照它们在类中声明的顺序在堆栈上一样,包括堆栈展开。我什至有一张照片: 在此处输入图像描述

析构函数的工作原理大致相似,但相反,但如果析构函数是虚拟的,则可能会更加复杂。如果析构函数是虚拟的,那么有三个部分。当有人调用析构函数时,会调用一个“存根”析构函数,该析构函数分派给最派生类型的“真实”析构函数。“真正的”析构函数调用你的析构函数“body”,然后按照它们在类中声明的相反顺序析构成员​​,然后析构基类(仍然以相反的顺序,与堆栈相同)。

*QuestionC 正确地观察到静态成员完全独立于我在此处编写的所有内容。

于 2014-06-27T17:45:55.043 回答
0

成员对象(除非它们是static)在调用类构造函数时构造。您看到的行为是正常且正确的。

构造函数完成后,成员对象不会被销毁。它们在调用类析构函数时被销毁(以相反的构造顺序)。

于 2014-06-27T17:49:24.013 回答