零初始化和本地范围静态变量的静态初始化

时间:2013-07-23 03:35:31

标签: c++ static initialization global-variables

我在Google上阅读了几篇关于 C ++初始化的帖子,其中一些帖子指的是StackOverflow。我从这些帖子中挑选的概念如下:

  • C ++初始化的顺序是:
    1. 零初始化;
    2. 静态初始化;
    3. 动态初始化
  • 静态对象(包含变量)首先是零初始化,然后是静态初始化

我有几个关于初始化问题的查询(存储类问题也可能相关):

  • 全局对象(不使用 static 关键字定义)也是静态对象,对吗?
  • 全局对象也会像上面的两个步骤一样初始化为静态对象,对吗?
  • 什么是静态初始化?它是指初始化静态对象(使用 static 关键字定义)吗?
  • 我还读到当执行线程首次进入块时,使用 static 关键字在块(即在函数中)中定义的对象被初始化!这意味着主要函数执行之前未初始化本地静态对象。这意味着它们没有被初始化为上面提到的两个步骤,对吗?
  • 动态初始化是指初始化由 new 运算符创建的对象,对吧?它可能会引用初始化,如myClass obj = myClass(100);myClass obj = foo();

我对初始化和存储类说明符问题的查询太多了。我阅读了C ++ 2003标准文档,但由于它们分散在整个文档中,所以无法找到明确的逻辑。

我希望你给我一个答案,逻辑解释存储类说明符和初始化的整个映射。欢迎任何参考!

可能解释我的问题的代码:

class myClass{
public:
   int i;
   myClass(int j = 10): j(i){}
   // other declarations
};

myClass obj1;//global scope
static myClass obj2(2);//file scope
{   //local scope
   myClass obj3(3);
   static myClass obj4(4);
}

修改 的:
如果您认为我的问题相当繁琐,您可以根据上述代码帮助解释您的想法。

2 个答案:

答案 0 :(得分:19)

  

我在Google上阅读了几篇关于 C ++初始化的帖子,其中一些帖子指的是StackOverflow。我从这些帖子中挑选的概念如下:

     
      
  • C ++初始化的顺序是:      
        
    1. 零初始化;
    2.   
    3. 静态初始化;
    4.   
    5. 动态初始化
    6.   
  •   

是的,确实有三个阶段(标准中)。让我们在继续之前澄清它们:

  • 零初始化:内存在字节级填充0。
  • 常量初始化:在对象的内存位置复制预先计算的(编译时)字节模式
  • 静态初始化:零初始化,然后是常量初始化
  • 动态初始化:执行函数以初始化内存

一个简单的例子:

int const i = 5;     // constant initialization
int const j = foo(); // dynamic initialization
  
      
  • 静态对象(包含变量)首先是零初始化,然后是静态初始化
  •   

是和否。

标准规定对象首先进行零初始化,然后是:

  • 如果可能,不断初始化
  • 否则动态初始化(编译器无法在编译时计算内存内容)

注意:在初始化不变的情况下,编译器可能会忽略按照as-if规则的第一个零初始化内存。

  

我有几个关于初始化问题的查询(存储类问题也可能相关):

     
      
  • 全局对象(不使用 static 关键字定义)也是静态对象,对吗?
  •   

是的,在文件范围内,static对象只是符号的可见性。可以通过名称从另一个源文件引用全局对象,而static对象名称对于当前源文件是完全本地的。

混淆源于在许多不同情况下重用世界static :(

  
      
  • 全局对象也会像上面的两个步骤一样初始化为静态对象,对吗?
  •   

是的,实际上是本地静态对象。

  
      
  • 什么是静态初始化?它是指初始化静态对象(使用 static 关键字定义)吗?
  •   

不,如上所述,它指的是在不执行用户定义的函数的情况下初始化对象,而是在对象的内存上复制预先计算的字节模式。请注意,对于稍后将动态初始化的对象,这只是将内存归零。

  
      
  • 我还读到当执行线程首次进入块时,使用 static 关键字在块(即在函数中)中定义的对象被初始化!这意味着主要函数执行之前未初始化本地静态对象。这意味着它们没有被初始化为上面提到的两个步骤,对吗?
  •   

它们是使用两个步骤进程初始化的,但实际上只有第一次执行才能通过它们的定义。所以过程是一样的,但时间略有不同。

在实践中,如果它们的初始化是静态的(即,内存模式是编译时模式)并且它们的地址未被采用,则它们可能会被优化掉。

请注意,在动态初始化的情况下,如果它们的初始化失败(应该初始化它们的函数抛出异常),则下次流量控制通过它们的定义时将重新尝试它。

  
      
  • 动态初始化是指初始化由 new 运算符创建的对象,对吧?它可能会引用初始化,如myClass obj = myClass(100);myClass obj = foo();
  •   

完全没有,它指的是初始化需要执行用户定义的函数(注意:就{C ++语言而言,std::string有一个用户定义的构造函数。)

编辑:我要感谢Zach,他指着我错误地将静态初始化称为C ++ 11标准称为常量初始化;现在应修复此错误。

答案 1 :(得分:-4)

我相信有三个不同的概念:初始化变量,变量在内存中的位置,变量初始化的时间。

首先:初始化

当在内存中分配变量时,典型的处理器会保持内存不变,因此变量将具有与其他人之前存储的值相同的值。为了安全起见,一些编译器添加了额外的代码来初始化它们分配给零的所有变量。我认为这就是“零初始化”的含义。当你说:

时会发生这种情况
 int i; // not all compilers set this to zero

但是如果你对编译器说:

 int i = 10;

然后编译器指示处理器将10放入内存而不是将其保留为旧值或将其设置为零。我认为这就是“静态初始化”的意思。

最后,你可以这样说:

 int i;
 ...
 ...
 i = 11;

然后处理器在执行int i;时“零初始化”(或保留旧值),然后当它到达行i = 11时它“动态初始化”变量为11(这可能发生很长时间)在第一次初始化之后。

第二:变量的位置

有:基于堆栈的变量(有时称为静态变量)和内存堆变量(有时称为动态变量)。

可以使用以下方法在堆栈段中创建变量:

int i;

或像这样的内存堆:

int *i = new int;

不同之处在于,在退出函数调用后,堆栈段变量将丢失,而内存堆变量将保留,直到您说出delete i;为止。您可以阅读汇编语言书籍以更好地理解差异。

第三:变量初始化的时间

当您输入在其中定义的函数调用时,堆栈段变量为“零初始化”或静态初始化。

new运算符首次创建内存堆变量时,它是“零初始化”或静态初始化的。

最后备注

您可以将static int i;视为全局变量,其范围仅限于其定义的函数。我认为关于static int i;的混淆是因为静态听觉意味着另一件事(它没有被破坏)退出例程时,它保留其值)。我不确定,但我认为static int i;使用的技巧是把它放在main()的堆栈中,这意味着它不会被销毁,直到你退出整个程序(所以它保留了第一次初始化) ,或者可能是它存储在应用程序的数据段中。