为什么类的字段是自动对象?

时间:2014-06-27 17:39:27

标签: c++ stack exe raii stack-unwinding

在我的学习机制中,我发现在堆栈展开时会有对象字段的析构函数调用。让我明确解释一下:

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

所以,现在如果Lock_ptr的构造函数抛出一个exeption,对象 aa 将被销毁; 问题是"为什么"?我一直认为对象的文件不是通常的自动(lochal)对象。它们是在构造函数初始化它们之前创建的。所以它们在构造函数范围之外不能被破坏(否则它们将是建造者完成工作后立即销毁

3 个答案:

答案 0 :(得分:5)

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

如果X::bb的构造函数抛出异常,则意味着无法构造类型为X的完整对象。必须销毁已构建的所有子对象,例如X::aa,因为与完整对象具有相同存储持续时间的子对象在没有完整对象的情况下无法生存。

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

C ++的构造和销毁规则旨在保证,只要程序正常终止,所创建的每个对象也只会被销毁一次。这对于RAII成语至关重要。在此示例中,如果X::aa在构造资源时获取资源,则语言必须确保将释放这些资源。如果X::aa的构造失败时未调用X的析构函数,那么何时应该调用它?

答案 1 :(得分:3)

X有一个构造aabb的“真实”构造函数,然后调用X的构造函数体。这就是初始化列表在X的构造函数“body”之前的原因。在这个“真正的”构造函数内部,创建base和then成员,好像它们按照它们在类中声明的顺序在堆栈中,包括堆栈展开。我甚至有一张照片: enter image description here

除了反过来之外,析构函数的工作原理模糊不清,但如果析构函数是虚函数,则可能更复杂。如果析构函数是虚拟的,那么有三个部分。当有人调用析构函数时会调用一个“存根”析构函数,析构函数会调度到派生类型最多的“真正的”析构函数。 “真正的”析构函数调用你的析构函数“body”,然后按照它们在类中声明的相反顺序破坏成员,然后它破坏基类(仍然以相反的顺序,与堆栈相同)。 / p>

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

答案 2 :(得分:0)

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

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