C ++ - 析构函数调用顺序

时间:2017-11-24 09:10:09

标签: c++ destructor

我有以下C ++代码:

#include <iostream>
struct A 
{
    A() { std::cout << "A" << ++x; }
    A(int x) : A() { std::cout << x; }
    ~A() { std::cout << "D"; }
    static int x;
};

int A::x = 0;
struct B 
{
    A a, aa, aaa;
    B() : aa(1), a(2) { std::cout << "B" << std::endl; }
    ~B() { std::cout << "B" << A::x; }
};
B beta;

    int main()
    {
        return 0;
    }

除了析构函数调用之外,我理解控制流中的所有内容。 这是没有析构函数的控制流程:

  1. 创建对象B

  2. 调用构造函数B. 分别叫a,aa,aaa

  3. 2.1 for a,调用A(int x)

    2.2 aa,调用A(int x)

    2.3 aaa,请致电A()

    1. 显示B来自B身体
    2. 现在4.步骤是调用析构函数B,我知道。

      我不知道的是为A调用析构函数的顺序是什么。 分别是aa,aa,aaa还是aaa,aa,a?

      提前致谢。

3 个答案:

答案 0 :(得分:3)

成员对象以它们构造的相反顺序被销毁。请注意,您不会通过更改构造函数初始化列表中的顺序来影响此顺序。订单完全由您在struct / class定义中声明它们的顺序决定。

  

我不知道的是,为A调用析构函数的顺序是什么。分别是aa,aa,aaa还是aaa,aa,a?

因此,后一种情况正在发生。

答案 1 :(得分:1)

一切都很好看。它以堆栈方式构造 - 破坏(先入/最后出):

#include <iostream>
struct A 
{
    A() { name="untitled"; std::cout << name <<" constructor" << std::endl; }
    A(std::string name):name(name) { std::cout << name <<" constructor" << std::endl; }
    ~A() { std::cout << name <<" destructor" << std::endl; }
    std::string name;
};

struct B 
{
    A a, aa, aaa;
    B() : aa("aa"), a("a") { std::cout << "B constructor" << std::endl; }
    ~B() { std::cout << "B destructor" << std::endl; }
};
B beta;

int main()
{
    return 0;
}

结果:

a constructor
aa constructor
untitled constructor
B constructor
B destructor
untitled destructor
aa destructor
a destructor

这个订单有保证吗? yes

如果您打开所有警告,您会看到:

 g++ -Wall -Wreorder main.cpp 


main.cpp: In constructor ‘B::B()’:
main.cpp:12:10: warning: ‘B::aa’ will be initialized after [-Wreorder]
     A a, aa, aaa;
          ^
main.cpp:12:7: warning:   ‘A B::a’ [-Wreorder]
     A a, aa, aaa;
       ^
main.cpp:13:5: warning:   when initialized here [-Wreorder]
     B() : aa("aa"), a("a") { std::cout << "B constructor" << std::endl; }
     ^

答案 2 :(得分:1)

这需要永远来查找,但是根据n4659(ISO C ++ 17草案):

  

15.6.2初始化基础和成员

     

第(13.3)段

     

然后,非静态数据成员按照它们在类定义中声明的顺序进行初始化(同样不管mem-initializers的顺序如何)。

     

[注意:声明命令的目的是确保基础和成员子对象在销毁中被销毁   初始化的逆序。 - 结束说明]

这里,mem-initializers是构造函数定义中冒号后面的列表。