对于以下代码段:
class Bar {
public:
int x;
int y;
Bar(int _x, int _y) { /* some codes here */ ...}
};
class Foo {
public:
int x;
int y;
int z;
Foo(Bar b):x(b.x), y(b.y)
{
z = someFunction(x, y);
}
};
void f(int x, int y)
{
Bar b(x, y);
static Foo x(b);
}
int main()
{
f(2, 3);
}
在我看来,函数内部的静态变量应该在main()
之前初始化。但是,x
类型的静态变量Foo
取决于b
类型的局部变量Bar
。
问题是:
1)x
的构造函数何时执行?即,x
是否首次调用局部变量b
进行初始化?我不想要一些特殊编译器案例的特定结果,但想知道它是否在C ++语言中定义良好。
2)这是一个有效的程序吗?
3)这是一个很好的做法吗?
答案 0 :(得分:3)
在我看来,函数内部的静态变量应该在main()
之前初始化
你的思想是错误的......至少部分是这样。静态局部变量可以在某些情况下尽早初始化,但在构造函数依赖于本地变量(例如此变量)的情况下则不会。
n3242标准草案§6.7/ 4:
...允许实现在静态或线程存储持续时间内执行其他块范围变量的早期初始化,条件是允许实现在命名空间范围内静态初始化具有静态或线程存储持续时间的变量( 3.6.2)。否则,在第一次控制通过其声明时初始化这样的变量; ...
为了完整性,这里是常量(静态)初始化§3.6.2/ 2的要求:
执行常量初始化:
- 如果每个完整表达式(包括隐式转换)出现在引用的初始值设定项中 static或thread storage duration是一个常量表达式(5.19),引用绑定到左值 指定具有静态存储持续时间或临时的对象(见12.2);
- 如果构造函数调用初始化具有静态或线程存储持续时间的对象,则构造函数为 一个constexpr构造函数,如果所有构造函数参数都是常量表达式(包括转换), 如果,在函数调用替换(7.1.5)之后,每个构造函数调用和完全表达式 mem-initializers是一个常量表达式;
- 如果构造函数调用未初始化具有静态或线程存储持续时间的对象,并且每个对象都是如此 初始化程序中出现的完整表达式是一个常量表达式。
1)x
在第一次执行到达它的声明时初始化,并且在构造函数运行时。因此,当b
的初始化开始时,x
已完全初始化。
2)就初始化依赖性而言,是的。
3)当然,如果需要,静态本地对象的构造函数可能依赖于本地对象。只要在超出范围之后不引用该本地对象。在这种情况下,您只需复制其成员,因此在构建x
后您不依赖它。
答案 1 :(得分:1)
根据C ++标准(6.7声明声明)
4所有块范围变量的零初始化(8.5) 静态存储持续时间(3.7.1)或线程存储持续时间(3.7.2)是 在任何其他初始化发生之前执行。 ...除此以外 在控件第一次通过时初始化这样的变量 它的声明;这样的变量被认为是初始化的 完成初始化。如果初始化退出 抛出异常,初始化不完整,所以会 下次控制进入声明时再试一次。 ...
因此在函数获取控件之前,局部静态变量是零初始化的,然后当函数获得控件时,它们将使用它们的初始化器(或构造函数)进行初始化。
答案 2 :(得分:0)
Vlad在C ++标准中找到了很多参考资料。
现在提出您的问题:
x
的构造函数?:根据Vlad的回答,它会在您第一次调用f
时执行,而x将会执行然后通过任何其他电话保持其价值f
,x
in已经是一个参数。但是,使用第一次调用时传递的值初始化静态变量