在构造函数的初始化程序列表中是否调用了函数?

问题描述:

考虑:在构造函数的初始化程序列表中是否调用了函数?

int f() { 
    static int i = 0; 
    return i++; 
} 

struct Test { 
    int a, b; 
    Test() : a(f()), b(f()) {} 
}; 

Test t; 

我知道ab之前,由于其在struct声明的顺序初始化。

我也知道fg(f(), f())的两个调用是不确定的。

所以我想知道是否保证t.a == 0t.b == 1

+0

@FrançoisAndrieux我不认为它是重复的。这个问题是专门处理成员初始化列表中函数调用的顺序,这不是问题处理的问题。 – Xirema

+0

@FrançoisAndrieux - 不要认为这是一个重复。 OP知道'a'在'b'之前被初始化。但问是否对'f()'进行了两次调用是否被排序。在'a'或'b'被初始化之前,'f()'可能会被调用两次。 –

+1

我需要验证,但我相信他们是。 –

所以我想知道是否保证t.a == 0t.b == 1

这将始终是真实的,只要ab之前在类声明中,并没有别的要求的ab初始化之间f()。类成员按照它们在类中声明的顺序进行初始化。 [class.base.init]/11:

在非委托构造函数,以下列顺序进行初始化:[...]

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

如此以来ab之前那么当构造函数初始化a它会调用f()在第一时间,然后当它初始化b将其称之为第二次。

我们也知道有成员初始化之间的序列点,是因为[class.base.init]/7:

[...]由每个MEM-初始化执行的初始化构成一个完整的表达。在mem-initializer中的任何表达式都将作为执行初始化的完整表达式的一部分进行评估。

告诉我们每个初始化为全表达和每个全表达进行测序:[intro.execution]/14

有全表达相关的每个值的计算和副作用进行测序之前每值计算和与要评估的下一个完整表达式相关的副作用。

+0

绝妙的答案!但是,当然,只有当'f()'在其他任何地方被调用,特别是在没有其他静态初始化程序时:-) – Christophe

+0

@Christophe谢谢。我也加了一点点珍闻。 – NathanOliver

我知道a在b之前被初始化,因为它们在struct中声明的顺序。

确实如此。

我对该约束的解释是a无法在b之前初始化,除非在b初始化之前初始值表达式的评估已完成。

我没有在标准中看到任何说到对用于初始化非静态成员的表达式进行评估的顺序。然而,我看到在C++ 11标准(12.6.2/12)下面的例子:

名称在表达式列表或MEM-初始化的支撑-INIT-list的范围被评估为其指定了mem初始值设定项的构造函数。 [实施例

class X { 
    int a; 
    int b; 
    int i; 
    int j; 
    public: 
    const int& r; 
    X(int i): r(a), b(i), i(i), j(this->i) { } 
}; 

除非的this->i评价i初始化后进行测序这将是无效的。