10

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

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

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

  • 全局对象(没有静态关键字定义)也是静态对象,对吧?
  • 全局对象也像静态对象一样通过上面的两个步骤进行初始化,对吧?
  • 什么是静态初始化?它是指初始化静态对象(用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);
}

编辑
如果您认为我的问题相当乏味,您可以根据上面的代码帮助解释您的想法。

4

2 回答 2

20

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

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

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

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

一个简单的例子:

int const i = 5;     // constant initialization
int const j = foo(); // dynamic initialization
  • 静态对象(包括变量)首先是Zero-initialized,然后是Static-initialized

是和不是。

该标准要求对象首先进行零初始化,然后它们是:

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

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

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

  • 全局对象(没有静态关键字定义)也是静态对象,对吧?

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

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

  • 全局对象也像静态对象一样通过上面的两个步骤进行初始化,对吧?

是的,事实上,本地静态对象也是如此。

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

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

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

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

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

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

  • 动态初始化是指对new操作符创建的对象进行初始化,对吧?它可能指的是初始化,如myClass obj = myClass(100);myClass obj = foo();

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

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

于 2013-07-23T07:12:13.933 回答
-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()这意味着在退出整个程序之前它不会被销毁(因此它保留第一次初始化),或者它可能存储在应用程序的数据段。

于 2013-07-23T04:49:51.007 回答