为什么gcc接受将方法中的静态变量初始化为对象的字段?

hgtggwj0  于 2023-10-19  发布在  其他
关注(0)|答案(2)|浏览(106)
class MyClass {
public:
    int obj_field;

    MyClass(int val) : obj_field(val) {}

    void myMethod() {
        static int my_static_var = obj_field;  // <--- Why is this okay?
        // ... 
    }
};

我确信这是错误的,不应该编译,因为我确信它们只能初始化为constexpr(假设值在执行开始之前初始化)。令我惊讶的是,它在gcc 9.4.0,C++17下编译没有错误。它是否能够推迟静态变量的初始化,直到第一次调用或未定义的行为更有可能?
我知道,如果它能工作的话,静态值可能会从调用方法的第一个对象中选取。

ovfsdjhp

ovfsdjhp1#

(假设值在执行开始前初始化)
这个假设(可能)有两点不成立。
首先,在函数内部初始化static变量的时间与在命名空间范围内初始化static变量的时间不同。虽然全局静态变量(大部分)在main执行之前初始化(我猜这就是您所想的),但局部静态变量直到其定义执行时才初始化。这意味着它直到(至少)第一次调用函数时才被初始化。
第二,execution does not begin with the main function。全局static变量的初始化分为两个阶段。第一阶段处理您知道的常量表达式初始化。第二阶段是针对那些需要执行代码来构造的变量。第二阶段可以在main函数开始之前完成。(有一些余地,允许第二级在main的开始处放气。
实际上,在初始化全局static变量时执行代码的能力是static-order-fiasco中的一个关键要素。更好的是,解决某些静态顺序失败的一种方法是通过将static变量定义 Package 在getter函数中来控制初始化顺序。这确保了变量在第一次调用函数时被初始化,这必然是在第一次使用变量的值之前。所以你可以说,在你的问题中,你解决了一个你不知道存在的问题。:)

  • 对于那些喜欢实验的人,* 这里有一个简单的例子,展示了命名空间范围内的static变量可以用非常量表达式初始化。
#include <chrono>
#include <iostream>

static const auto start_time =
    std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());

int main() {
    std::cout << "Program started at: " << std::ctime(&start_time) << "\n";
}
  • 直接回答问题:*

是的,my_static_var的初始化被推迟到第一次调用myMethod(),并且值将来自该调用的*this对象。

参见When do function-level static variables get allocated/initialized?

jfgube3f

jfgube3f2#

它是否能够将静态变量的初始化推迟到第一次调用
这实际上是一个 local 静态变量初始化的时候。更具体地说,初始化发生在执行第一次到达声明点时。
或未定义的行为更有可能?
这个例子中没有UB。
为什么gcc接受将方法中的静态变量初始化为对象的字段?
因为这样做是很好的。

相关问题