Any*_*orn 5 c++ static compiler-optimization
在以下情况下应该采取什么行为:
class C {
boost::mutex mutex_;
std::map<...> data_;
};
C& get() {
static C c;
return c;
}
int main() {
get(); // is compiler free to optimize out the call?
....
}
Run Code Online (Sandbox Code Playgroud)
编译器是否允许优化对 的调用get()?
这个想法是在多线程操作需要静态变量之前对其进行初始化
这是更好的选择吗?:
C& get() {
static C *c = new C();
return *c;
}
Run Code Online (Sandbox Code Playgroud)
在 C++23 (N4950) 中,当进入静态局部变量的包含块时,可以观察到初始化静态局部变量的任何副作用。因此,除非编译器可以确定初始化变量没有明显的副作用,否则它将必须生成代码以便get()在适当的时间调用(或执行 的内联版本get(),视情况而定)。
与早期标准相反,C++ 23 不再允许“提前”完成静态局部变量的动态初始化(如下所述)。
[stmt.dcl]/3:
具有静态存储持续时间(6.7.5.2)或线程存储持续时间(6.7.5.3)的块变量的动态初始化在控制第一次通过其声明时执行;这样的变量在初始化完成后就被认为已初始化。
C 和 C++ 标准在一个相当简单的原则下运行,通常被称为“as-if 规则”——基本上,编译器可以自由地做几乎任何事情,只要没有一致的代码可以辨别它所做的和所做的之间的差异。被正式要求。
我没有看到一种方法可以让符合代码来辨别get在这种情况下是否实际被调用,所以在我看来,可以自由地对其进行优化。
至少在 N4296 中,该标准包含对静态局部变量进行早期初始化的显式许可:
具有静态存储持续时间的块范围实体的常量初始化(3.6.2)(如果适用)在首次进入其块之前执行。允许实现对具有静态或线程存储持续时间的其他块作用域变量执行早期初始化,其条件与允许实现在命名空间范围内静态初始化具有静态或线程存储持续时间的变量的条件相同(3.6.2)。否则,此类变量将在控制第一次通过其声明时被初始化;这样的变量在初始化完成后就被认为已初始化。
因此,根据此规则,局部变量的初始化可以在执行的早期任意发生,因此即使它具有明显的副作用,它们也可以在任何尝试观察它们的代码之前发生。因此,您不能保证看到它们,因此允许对其进行优化。