成员初始值设定项列表中的计算顺序是什么?

What is the order of evaluation in a member initializer list?

提问人:hookenz 提问时间:8/7/2009 最后编辑:Jan Schultkehookenz 更新时间:7/26/2023 访问量:85318

问:

我有一个构造函数,它接受一些参数。我假设它们是按列出的顺序初始化的,但在一种情况下,它们似乎是反向初始化的,导致中止。当我反转参数时,程序停止中止。

下面是我使用的语法示例。 在这种情况下,需要先初始化。你能确保这个初始化顺序吗?a_b_

class A
{
  public:
    OtherClass a_;
    AnotherClass b_;

    A(OtherClass o, string x, int y)
      : a_(o)
      , b_(a_, x, y) {}
};
C GCC 构造函数 初始化 C++-FAQ

评论

6赞 Rob Kennedy 8/7/2009
你说你询问的是构造函数参数,但在你到达构造函数之前,它们就被计算了,而且它们以未指定的、由编译器确定的顺序计算。但是你真的在问初始化列表的顺序,所以我为你更改了问题标题。
1赞 Sunil Kartikey 9/19/2020
:),我在一次采访中被问到这个问题
0赞 hookenz 9/19/2020
面试官可能从这里得到了这个问题:)
0赞 LandonZeKepitelOfGreytBritn 7/20/2022
@hookenz 不,我们没有。

答:

336赞 Khaled Alshaya 8/7/2009 #1

它取决于类中数据成员声明的顺序。所以将是第一个,然后是你示例中的第二个。a_b_

评论

32赞 Greg Hewgill 8/7/2009
事实上,如果声明与构造函数初始值设定项列表中的顺序不同,好的编译器会发出警告。例如,请参阅 gcc。-Wreorder
271赞 AProgrammer 8/7/2009
它们按成员声明顺序而不是按构造函数中的顺序构造的原因是,一个构造函数可能有多个构造函数,但只有一个析构函数。析构函数按照构造的顺序销毁构件。
4赞 11/5/2018
我们的意思是......声明的顺序相反。不是“构造”,析构函数不可能看到构造函数就知道了,不是吗?
0赞 SusanW 11/18/2023
@user337598是的,有点。我认为 AProgrammer 是指实际物理初始化意义上的“构造”(正如您所建议的那样,它以声明的顺序发生),而不是“出现在某些构造函数的初始化列表中的顺序”的意义上。你的措辞更清晰。
222赞 GManNickG 8/7/2009 #2

引用标准,澄清一下:

12.6.2.5

初始化应按以下顺序进行:

...

  • 然后,应按照非静态数据成员在类定义中声明的顺序对其进行初始化 (同样,无论 mem-initializers 的顺序如何)。

...

31赞 Adam Getchell 8/17/2016 #3

现在,这方面的标准参考似乎是 12.6.2 第 13.3 节:

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

0赞 SolomidHero 7/26/2023 #4

看到其他答案,而没有太多关于其他成员初始化的细节,我建议从标准参考 12.6.2 第 13 节中阅读更多信息(感谢 @Adam Getchell 提供的链接):

在非委托构造函数中,初始化按以下顺序进行:

(13.1) — 首先,并且仅针对最派生类 (1.8) 的构造函数,
虚拟基类在 它们在基类的有向无环图的深度优先从左到右遍历中出现的顺序, 其中“从左到右”是派生类 base-specifier-list 中基类的出现顺序。

(13.2) — 然后,直接基类按照它们在 base-specifier-list
中出现的声明顺序进行初始化(无论 mem-initializer 的顺序
如何)。

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

(13.4) — 最后,执行构造函数主体的复合语句

术语:

base-specifier-list - 派生类的基类列表。请参阅参考文献第 10 节。
示例:公共虚拟 B、私有 C
class A :

mem-initializers - 类成员的初始值设定项列表。
示例:number(1.0f), text(“abc”)
A::A() : { /* ... */}

compound-statement - 块,即构造函数的主体。{}


仅此而已,简单地说了命令:

  1. 静态变量(参见这个stackoverflow问题C++静态变量初始化顺序,还有那个有趣的行为SIOF)。在单个翻译单元中,顺序遵循声明顺序,在不同的 - 编译器决定。
  2. DFS 显示的虚拟基类
  3. 按派生列表中的顺序指定的直接基类
  4. 非静态变量按声明(! 不是初始值设定项顺序)顺序