对于以下代码段:
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()
之前就应该初始化。 但是,Foo
类型的静态变量x
取决于 Bar
类型的局部变量b
。
问题是:
1) x
的构造函数何时执行? 即x
是否通过第一次调用局部变量b
初始化? 我不想要一些特殊编译器案例的特定结果,但想知道它是否在C++语言中定义良好。
2)它是一个有效的程序吗?
3)这是一个很好的做法?
在我看来,函数中的静态变量甚至在 main() 之前就应该初始化
你的思想不正确...至少部分。在某些情况下,静态局部变量可能会提前初始化,但在构造函数依赖于局部变量(如本变量)的情况下则不然。
N3242 标准草案 §6.7/4:
。允许实现在允许在命名空间作用域 (3.6.2) 中静态初始化具有静态或线程存储持续时间的变量的相同条件下,使用静态或线程存储持续时间执行其他块范围变量的早期初始化。否则,此类变量在控件第一次通过其声明时初始化;...
为了完整起见,以下是常量(静态)初始化 §3.6.2/2 的要求:
执行常量初始化:
— 如果引用的初始值设定项中显示的每个完整表达式(包括隐式转换) 静态或线程存储持续时间是常量表达式 (5.19),引用绑定到左值 指定具有静态存储持续时间或临时存储的对象(见12.2);
— 如果具有静态或线程存储持续时间的对象由构造函数调用初始化,如果构造函数是 一个 constexpr 构造函数,如果所有构造函数参数都是常量表达式(包括转换), 如果在函数调用替换 (7.1.5) 之后,每个构造函数调用和 mem 初始值设定项是一个常量表达式;
— 如果具有静态或线程存储持续时间的对象未由构造函数调用初始化,并且如果 其初始值设定项中显示的完整表达式是一个常量表达式。
1) x
在执行第一次到达其声明时初始化,这就是构造函数运行时。因此,当x
的初始化开始时,b
将完全初始化。
2)就初始化依赖关系而言,是的。
3)当然,如果需要,静态本地对象的构造函数可能依赖于本地对象。只要您不引用该本地对象后它超出范围。在这种情况下,您只需复制它的成员,因此在构造x
后您不会依赖它。
根据C++标准(6.7声明声明)
因此,在函数获取控件4 所有块范围变量的零初始化 (8.5) 静态存储持续时间 (3.7.1) 或线程存储持续时间 (3.7.2) 为 在进行任何其他初始化之前执行。...否则 这样的变量在控件第一次通过时初始化 其声明;这样的变量被认为是在 完成其初始化。如果初始化退出时间 抛出异常,初始化未完成,因此它将 下次控件进入声明时重试。...
之前,局部静态变量为零初始化,然后当函数获取控件时,它们使用其初始值设定项(或构造函数)进行初始化。
Vlad 做了在标准中寻找参考文献C++困难的部分。
现在回答您的问题:
-
x
的构造函数何时执行?:根据 Vlad 的回答,它将在您第一次调用f
时执行,然后 x 将通过任何其他调用保留其值 -
它是一个有效的程序吗?:当前程序不编译器,但对于其他错误:x 和 y 在 bar 中是私有的,在
f
中是私有的,x
已经是一个参数。但是使用第一次调用时传递的值初始化静态变量是可以
的 - 这是一个好的做法吗?:这不是一个常见的用法,所以必须在评论中为关注的读者或维护者解释。除此之外,只要您知道为什么要使用此结构,它就没有任何问题。