如下代码,第一次调用 fn 时会执行 get_value ,后续调用不会执行:
void fn() {
static int x = get_value();
// ...
}
如果代码里显示调用该函数,编译器可能会优化,在第一次调用前初始化。
但如果通过函数指针动态调用,或者将该函数对外导出,那么每次调用 fn 时是否都要判断一下有没有初始化?
1
BingoXuan 2023-07-17 11:46:06 +08:00
op 的例子编译出错,initializer element is not constant 。
不如改成 static int x; static int is_initialized = 0; if (!is_initialized) { x = get_value(); is_initialized = 1; } |
2
Inn0Vat10n 2023-07-17 12:05:20 +08:00
每次调用 fn 都有额外开销的,比较常见的场景是用这种方式实现的单例模式
?t=1143 |
3
tool2d 2023-07-17 12:11:20 +08:00
@BingoXuan 我看 VC 反编译汇编代码,编译器有自动包含 is_initialized ,就在 static int x 内存地址的前面。
如果调用了 get_value 后,这个匿名地址( u8 )会被赋值为 1 ,证明这个 x 已经被初始化过一次了。 每次 fn 进入后,都会先判断这个地址是 0 (变量未初始化),还是 1 (已初始化) |
4
codehz 2023-07-17 13:53:38 +08:00
|
5
lakehylia 2023-07-17 14:11:40 +08:00
@codehz Starting in C++11, a static local variable initialization is guaranteed to be thread-safe
|
6
Shatyuka 2023-07-17 14:13:11 +08:00
“如果代码里显示调用该函数,编译器可能会优化,在第一次调用前初始化。” 举个例子?初始化成常量?
8.8.4: Dynamic initialization of a block-scope variable with static storage duration (6.7.5.1) or thread storage duration (6.7.5.2) is performed the first time control passes through its declaration; such a variable is considered initialized upon the completion of its initialization. |
7
mogg 2023-07-17 14:22:46 +08:00 1
1. static 对象的存储在程序开始时分配,并在程序结束时解分配
2. 控制流首次经过变量声明时才会被初始化,之后所有调用都会跳过 3. c++的话,c++11 之前这样不是线程安全的(即多个线程试图同时初始化),c++11 之后线程安全。c 的话不太确定 4. 不确定你的“零开销” 是什么含义,c++里如果你的 get_value 是 consteval 的,会在编译期执行完,但是 c 里吗应该是在运行时执行一次 |