繁体   English   中英

局部范围静态变量的零初始化和静态初始化

[英]zero initialization and static initialization of local scope static variable

我从Google阅读了有关C ++初始化的几篇文章,其中一些将我引到StackOverflow上。 我从这些帖子中挑选的概念如下:

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

我有一些关于初始化问题的查询( 存储类问题也可能与此有关):

  • 全局对象 (未使用static关键字定义)也是静态对象,对吗?
  • 全局对象也像静态对象一样通过上述两个步骤初始化,对吗?
  • 什么是静态初始化 它是否涉及初始化静态对象(使用static关键字定义)?
  • 我还读到了在执行线程首次进入该块时,使用static关键字在块内(即在函数中)定义的对象已初始化! 这意味着本地静态对象不会在执行函数之前初始化。 这意味着它们没有被初始化为上述两个步骤,对吗?
  • 动态初始化是指由操作员创建的对象的初始化,对吗? 它可能像myClass obj = myClass(100);一样引用初始化myClass obj = myClass(100); myClass obj = foo();

我对初始化和存储类说明符问题有太多咨询。 我阅读了C ++ 2003 Standard文档,但找不到清晰的逻辑,因为它们分散在整个文档中。

我希望您能给我一个答案, 从逻辑上解释存储类说明符和初始化的整个过程。 欢迎任何参考!

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

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);
}

编辑
如果您认为我的问题很繁琐,可以根据上述代码帮助解释您的想法。

我从Google阅读了有关C ++初始化的几篇文章,其中一些将我引到StackOverflow上。 我从这些帖子中挑选的概念如下:

  • C ++的初始化顺序为:
    1. 零初始化 ;
    2. 静态初始化 ;
    3. 动态初始化

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

  • 零初始化:存储器在字节级别填充为0。
  • 常量初始化:将预先计算的(编译时)字节模式复制到对象的内存位置
  • 静态初始化:零初始化,然后进行常量初始化
  • 动态初始化:执行一个函数来初始化内存

一个简单的例子:

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

是的,没有。

该标准要求首先将对象初始化为零,然后将它们初始化为:

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

注意:在进行常量初始化的情况下,编译器可能会遵循as-if规则而忽略第一个零初始化的内存。

我有一些关于初始化问题的查询( 存储类问题也可能与此有关):

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

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

混乱源于在许多不同情况下对世界static的重用:

  • 全局对象也像静态对象一样通过上述两个步骤初始化,对吗?

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

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

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

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

尽管实际上只有第一次执行通过了它们的定义,但它们是通过两步过程进行初始化的。 因此,过程相同,但时间略有不同。

但是实际上,如果它们的初始化是静态的(即,内存模式是编译时模式)并且不占用其地址,则可以将它们优化。

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

  • 动态初始化是指由操作员创建的对象的初始化,对吗? 它可能像myClass obj = myClass(100);一样引用初始化myClass obj = myClass(100); myClass obj = foo();

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

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

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

第一:初始化

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

 int i; // not all compilers set this to zero

但是,如果您对编译器说:

 int i = 10;

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

最后,您可以这样说:

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

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

第二:变量的位置

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

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

int i;

或像这样的内存堆:

int *i = new int;

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

第三:变量初始化的时间

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

new操作符首次创建内存堆变量时,该变量将被“零初始化”或“静态初始化”。

最后的话

您可以考虑一下static int i; 作为一个全局变量,范围仅限于定义它的功能static int i; 之所以会这样,是因为“静态听到”意味着另一件事(退出例程时它不会被破坏,因此它保留了其价值)。 我不确定,但我认为static int i;的技巧是 是将其放入main()的堆栈中,这意味着直到您退出整个程序(它保留第一个初始化),它才会被销毁,或者它可能存储在应用程序的数据段中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM