【问题标题】:Order of member constructor and destructor calls成员构造函数和析构函数调用的顺序
【发布时间】:2011-01-16 06:59:09
【问题描述】:

哦,C++ 大师,我寻求您的智慧。跟我说标准话,告诉我 C++ 是否保证以下程序:

#include <iostream>
using namespace std;

struct A
{
    A() { cout << "A::A" << endl; }
    ~A() { cout << "A::~" << endl; }
};

struct B
{
    B() { cout << "B::B" << endl; }
    ~B() { cout << "B::~" << endl; }
};

struct C
{
    C() { cout << "C::C" << endl; }
    ~C() { cout << "C::~" << endl; }
};

struct Aggregate
{
    A a;
    B b;
    C c;
};

int main()
{
    Aggregate a;
    return 0;
}

总会产生

A::A
B::B
C::C
C::~
B::~
A::~

也就是说,成员是否保证按声明顺序初始化并按相反顺序销毁?

【问题讨论】:

  • 当类变得庞大而笨重时,这是一个相当常见的细微错误原因。当您有 50 个数据成员,并且其中很多在构造函数初始化器列表中进行了初始化时,很容易假设构造顺序是初始化器列表中的顺序。毕竟,代码编写者已经仔细排序了列表......不是吗?

标签: c++


【解决方案1】:

是的,是的。对于成员变量,销毁的顺序总是与构造的顺序相反。

【讨论】:

    【解决方案2】:

    是的,它们是(即非静态成员)。初始化(构造)参见 12.6.2/5,销毁参见 12.4/6。

    【讨论】:

      【解决方案3】:

      也就是说,成员是否保证按声明顺序初始化并按相反顺序销毁?

      两者都是。见 12.6.2

      6 初始化应在 以下顺序:

      • 首先,并且仅用于 派生最多的构造函数 类如下所述,虚拟基 类应在初始化 它们以深度优先的顺序出现 从左到右遍历 基的有向无环图 类,其中“从左到右”是 基类的出现顺序 派生类中的名称 基本说明符列表。

      • 然后,直接 基类应在初始化 出现的申报顺序 基本说明符列表(无论 mem-initializers 的顺序)。

      • 那么,非静态数据成员应该是 按它们的顺序初始化 在类定义中声明 (再次不管的顺序 内存初始化器)。

      • 最后, 构造函数的复合语句 身体被执行。 [注: 申报令的任务是 确保基础和成员子对象 以相反的顺序销毁 初始化。 ——尾注]

      【讨论】:

      • 如果我没记错的话,两者都是...可以把它想象成一个堆栈。先推,最后弹出。因此,在实例化您的第一个实例时,它会按堆栈的顺序被推送到内存中。然后,第二个被推过去,第三个被推到第二个上,依此类推。然后,在销毁您的实例时,程序将寻找第一个销毁的,最后一个被推送的。但是我这样解释可能是错误的,但这是我在做 C/C++ 和 ASM 时学习的方式。
      【解决方案4】:

      是的,标准保证对象按照它们创建的相反顺序被破坏。原因是一个对象可能使用另一个对象,因此依赖它。考虑:

      struct A { };
      
      struct B {
       A &a;
       B(A& a) : a(a) { }
      };
      
      int main() {
          A a;
          B b(a);
      }
      

      如果ab 之前销毁,那么b 将持有无效的成员引用。通过以与创建对象相反的顺序销毁对象,我们可以保证正确的销毁。

      【讨论】:

      • 我从没想过这条规则也适用于作用域成员的销毁顺序!
      猜你喜欢
      • 2013-06-24
      • 2012-04-10
      • 2022-01-23
      • 2018-05-13
      • 2016-03-18
      • 2011-11-24
      • 2013-04-14
      相关资源
      最近更新 更多