是否为全局常量 POD 类型执行静态初始值设定项?

Is a static initializer executed for global const POD type?

提问人:Sathwik Matsa 提问时间:7/25/2023 更新时间:7/25/2023 访问量:49

问:

继 https://meowni.ca/posts/static-initializers/ 之后,我正在尝试减少共享库中的静态初始值设定项,以缩短程序的启动时间。本文中的一个建议是避免将具有非平凡构造函数的对象作为静态对象。我正在尝试测量在实现相同的方法后,静态初始值设定项总数是否下降。

请考虑以下程序:

#include <iostream>

static const char foo[] = "1234567890";
static const std::string bar = "abcdefghij";

int main() {
    std::cout << foo << std::endl;
    std::cout << bar << std::endl;
}

当我编译和检查 ELF 时,我看到了两者的函数指针,并在 .init_array 部分中看到了据称包含静态初始值设定项的函数指针foobar

readelf -s .init_array ./a.out -W | egrep "foo|bar"
    11: 0000000000403010    11 OBJECT  LOCAL  DEFAULT   15 _ZL3foo
    12: 0000000000405200    32 OBJECT  LOCAL  DEFAULT   25 _ZL3bar

由于 foo 是编译时常量,它不应该需要静态初始值设定项,对吧?

C++ 静态 静态初始化

评论

0赞 Sam Varshavchik 7/25/2023
不,这些只是符号。这些符号所指的是一个不同的主题。除非您在某处看到显式构造的实际代码,否则它是静态初始化的。foo
1赞 Pepijn Kramer 7/25/2023
您还可以使用static constexpr std::string_view foo{"123456789"};

答:

3赞 user17732522 7/25/2023 #1

类型是 、琐碎还是 POD 都无关紧要。const

运行时是否可能发生动态初始化取决于初始化是否为常量表达式

foo示例中的初始化保证为常量表达式。

bar示例中的初始化保证不是 C++20 之前的常量表达式,并且可能是也可能不是 C++20 中的常量表达式(取决于具体实现方式,特别是是否将 SSO 用于初始化)。std::string

的输出不是为您提供动态初始值设定项,而只是提供全局对象本身的符号。您可以在符号的残缺名称中看到这一点,或者它说的是 而不是 .它与您的问题无关。readelfOBJECTFUNC

从 C++20 开始,您可以通过使用 声明变量来强制不会发生动态初始化。然后,要么保证没有动态初始化(因为初始值设定项是一个常量表达式),要么编译器将无法编译程序,让你知道为什么它不是常量表达式。constinit

也可能没有做你认为它在你的例子中所做的。 这里确定的是链接,而不是存储持续时间,所以它只是意味着 和 应该有内部而不是外部链接,这意味着如果在多个翻译单元中这样声明,它们将不是同一个变量。无论您是否使用 ,它们都具有静态存储持续时间,因为它们是在命名空间范围内声明的。staticstaticfoobarstatic