构造函数执行顺序/顺序:函数中静态变量(类实例)的依赖初始化



对于以下代码段:

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已经是一个参数。但是使用第一次调用时传递的值初始化静态变量是可以
  • 这是一个好的做法吗?:这不是一个常见的用法,所以必须在评论中为关注的读者或维护者解释。除此之外,只要您知道为什么要使用此结构,它就没有任何问题。

最新更新