如果我在函数内部有一个变量(比如一个大数组),那么将它声明为static
和constexpr
是否有意义? constexpr
保证数组是在编译时创建的,所以static
会无用吗?
void f() {
static constexpr int x [] = {
// a few thousand elements
};
// do something with the array
}
在生成代码或语义方面,static
实际上是在做什么吗?
简短的回答是,static
不仅有用,而且总是很需要。
首先,请注意static
和constexpr
完全相互独立。 static
定义了对象在执行期间的生命周期; constexpr
指定在编译期间对象应该可用。编辑和执行在时间和空间上都是不相交和不连续的。因此,一旦编制了该程序,constexpr
就不再适用了。
声明constexpr
的每个变量都是隐含的const
,但const
和static
几乎是正交的(除了与static const
整数的相互作用。)
C++
对象模型(§1.9)要求除位字段之外的所有对象占用至少一个字节的内存并具有地址;此外,在特定时刻在程序中可观察到的所有这些对象必须具有不同的地址(第6段)。这并不需要编译器在每次使用本地非静态const数组调用函数时在堆栈上创建一个新数组,因为编译器可以避免使用as-if
原则,前提是它可以证明没有其他此类对象可以被观察。
遗憾的是,这并不容易证明,除非函数是微不足道的(例如,它不会调用其体在翻译单元中不可见的任何其他函数),因为根据定义,数组或多或少是地址。因此,在大多数情况下,必须在每次调用时在堆栈上重新创建非静态const(expr)
数组,这样就无法在编译时计算它。
另一方面,所有观察者共享本地static const
对象,并且即使从未调用其定义的函数,也可以初始化该对象。因此,以上都不适用,并且编译器不仅可以自由生成它的单个实例;可以在只读存储中生成单个实例。
所以你绝对应该在你的例子中使用static constexpr
。
但是,有一种情况你不想使用static constexpr
。除非constexpr
声明的对象是ODR-used或声明static
,否则编译器可以根本不包含它。这非常有用,因为它允许使用编译时临时constexpr
数组,而不会用不必要的字节污染编译的程序。在这种情况下,您显然不想使用static
,因为static
可能会强制对象在运行时存在。