提问人:Sathwik Matsa 提问时间:7/25/2023 更新时间:7/25/2023 访问量:49
是否为全局常量 POD 类型执行静态初始值设定项?
Is a static initializer executed for global const POD type?
问:
继 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 部分中看到了据称包含静态初始值设定项的函数指针foo
bar
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 是编译时常量,它不应该需要静态初始值设定项,对吧?
答:
类型是 、琐碎还是 POD 都无关紧要。const
运行时是否可能发生动态初始化取决于初始化是否为常量表达式。
foo
示例中的初始化保证为常量表达式。
bar
示例中的初始化保证不是 C++20 之前的常量表达式,并且可能是也可能不是 C++20 中的常量表达式(取决于具体实现方式,特别是是否将 SSO 用于初始化)。std::string
的输出不是为您提供动态初始值设定项,而只是提供全局对象本身的符号。您可以在符号的残缺名称中看到这一点,或者它说的是 而不是 .它与您的问题无关。readelf
OBJECT
FUNC
从 C++20 开始,您可以通过使用 声明变量来强制不会发生动态初始化。然后,要么保证没有动态初始化(因为初始值设定项是一个常量表达式),要么编译器将无法编译程序,让你知道为什么它不是常量表达式。constinit
也可能没有做你认为它在你的例子中所做的。 这里确定的是链接,而不是存储持续时间,所以它只是意味着 和 应该有内部而不是外部链接,这意味着如果在多个翻译单元中这样声明,它们将不是同一个变量。无论您是否使用 ,它们都具有静态存储持续时间,因为它们是在命名空间范围内声明的。static
static
foo
bar
static
评论
foo
static constexpr std::string_view foo{"123456789"};