为什么静态变量的初始化仅限于常量表达式?

时间:2011-12-06 13:38:00

标签: c++ static

来自“C ++ Primer,5th Edition”,第407页:

  

所有静态持续时间变量共享以下两个初始化   特性:

     
      
  • 未初始化的静态变量的所有位都设置为0.

  •   
  • 静态变量只能用常量表达式初始化。

  •   
     

常量表达式可以使用文字常量,const和enum   常量和sizeof运算符。以下代码片段   说明了这些要点:

int x;                        // x set to 0
int y = 49;                   // 49 is a constant expression
int z = 2 * sizeof(int) + 1;  // also a constant expression
int m = 2 * z;                // invalid, z not a constant
int main() {...}

我的问题是 - 为什么这是标准?这是什么(实际)原因。

否则我们会受到什么伤害?

特别是,我发现很难找到无效的理由:

int m = 2 * z; // invalid, z not a constant

因为z本身在编译时已经知道。

答案:

简单地说,根据标准,不能保证在main的第一个陈述之前的指令将按顺序完成。 虽然所有静态存储都将在任何其他初始化之前进行零初始化,但可以保证。 这意味着在我给出的示例中:int m = 2 * z;是一个未定义的行为,m可以评估为2*0=0,也可以评估为2 *(2 * sizeof(int)+ 1)。 / p>

超出“C ++标准 - ANSI ISO IEC 14882 2003”3.6.2(第44页):

  

具有静态存储持续时间(3.7.1)的对象应进行零初始化   (8.5)在进行任何其他初始化之前。

     

...

     

允许实现执行a的初始化   命名空间范围的对象,静态存储持续时间为静态   初始化即使不需要进行这样的初始化也是如此   静态...

     

...

重要的一点:

  

因此,如果对象obj1的初始化引用了   具有静态存储持续时间的命名空间范围的对象obj2   可能需要动态初始化并在以后定义   相同的翻译单元,未指定是否为obj2的值   used将是完全初始化的obj2的值(因为obj2是   静态初始化)或仅仅是obj2的值   零initialized.`

进一步阅读有关此类问题:

http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.14

编辑:回答。 Pubby是正确的答案(并被接受)但我真的错过了“因此......”部分。另外,我认为我添加的链接可能很有用。

5 个答案:

答案 0 :(得分:4)

z已初始化为2 * sizeof(int) + 1,但稍后可将其更改为其他值。通过明确要求将const表达式作为初始化程序,很明显您将获得什么值。如果允许非常量表达式,则最终可能会根据初始化顺序使用不同的值。根据const的要求,你很清楚你得到了什么。

答案 1 :(得分:3)

静态初始化(技术上持续初始化)需要常量表达式,但静态存储持续时间变量不需要。

int x;                        // 0 initialized
int y = 49;                   // statically initialized
int z = 2 * sizeof(int) + 1;  // statically initialized
int m = 2 * z;                // dynamically or statically initialized
  

3.6.2归零,零初始化和常量初始化称为静态初始化;所有其他初始化是   动态初始化。在进行任何动态初始化之前,应执行静态初始化。

动态初始化可以依赖于在编译时无法确定的函数和其他东西。如果编译器可以确定结果,则允许编译器执行静态初始化。

您发布的示例将起作用,但它可能会导致更复杂的初始化问题,因为某些变量可以动态或静态初始化:

inline double fd() { return 1.0; }
extern double d1;
double d2 = d1; // unspecified:
// may be statically initialized to 0.0 or
// dynamically initialized to 1.0
double d1 = fd(); // may be initialized statically to 1.0

答案 2 :(得分:1)

引用的文字完全错了,而且一直都是。静态变量 可以使用您想要的任何表达式进行初始化(前提是 表达式本身是合法的,并且不使用其他变量 尚未初始化)。比如:

int i = f();

非常频繁,即使在命名空间范围内,当然也是静态的 具有类类型和用户定义构造函数的变量甚至更多 频繁。

答案 3 :(得分:0)

我能想到的唯一原因是static变量存储在可执行文件的.rdata段中,因为它是只读部分可执行文件,把那些更改的东西放在那里,没有任何意义。

但是,我可能错了。

答案 4 :(得分:0)

我认为你的例子是有效的。从14882年:2011年,

  

可以在翻译过程中评估常量表达式。

  

变量   在单个翻译单元中定义的有序初始化应按其顺序初始化   翻译单位中的定义。

在您的示例中,z和m位于相同的翻译单元中。所以我认为m是由一个常量表达式初始化的。