“静态初始化”究竟是什么意思?

时间:2013-02-26 16:40:37

标签: c++ c++11

我一直在读C ++ 11中的POD,我读过的几个地方已经说过一些关于支持静态初始化的POD。例如:

On StackOverflow

  

POD的想法是捕获基本上两个不同的属性:
   1. 支持静态初始化
   2.在C ++中编译POD为您提供与在C中编译的结构相同的内存布局。

(只有粗体部分是相关的)

On Wikipedia

  

可以静态初始化一个简单的类型。

显然我不明白静态初始化是什么。我认为制作一个全局变量是静态初始化的一个例子,但我可以做到以下但Foo不是POD:

#include <type_traits>
#include <iostream>

struct Foo {
  Foo() : x(0), y(0) {}
  int x;
  int y;
};

struct Bar {
  Bar() = default;
  int x;
  int y;
};

// Apparently the following two lines are not "static initialization" because
// Foo is non-POD yet we can still do this:
Foo f;
Bar b;

int main()
{
    if (std::is_pod<Foo>::value) std::cout << "Foo is a POD" << std::endl;
    else                         std::cout << "Foo is *not* a POD" << std::endl;

    if (std::is_pod<Bar>::value) std::cout << "Bar is a POD" << std::endl;
    else                         std::cout << "Bar is *not* a POD" << std::endl;
}

Output

  

Foo is *not* a POD
  Bar is a POD

那么究竟什么是静态初始化,它与琐碎的类有什么关系呢?例子很棒。

4 个答案:

答案 0 :(得分:5)

具有静态持续时间的对象的初始化分为两个阶段,静态初始化和动态初始化(请注意滥用术语 static :))。

动态初始化是指涉及调用函数的初始化,因此必须在运行时进行,与可以存储在可执行文件本身并刚刚加载的文字初始化相比较。

答案 1 :(得分:5)

静态初始化适用于具有静态或线程存储持续时间的变量。它分两个阶段发生。

首先,具有静态存储持续时间的变量在任何其他初始化之前都是零初始化的。

然后执行常量初始化。常量初始化必须是以下三种可能之一(§3.6.2/ 2):

  
      
  • 如果在具有静态或线程存储持续时间的引用的初始值设定项中出现的每个完整表达式(包括隐式转换)是常量表达式(5.19)并且引用绑定到使用静态指定对象的左值存储持续时间或临时(见12.2);

  •   
  • 如果具有静态或线程存储持续时间的对象由构造函数调用初始化,如果构造函数是constexpr构造函数,如果所有构造函数参数都是常量表达式(包括转换),并且在函数调用替换之后(如果7.1.5),mem-initializers和非静态数据成员的brace-or-equal-initializers中的每个构造函数调用和完全表达式都是一个常量表达式;

  •   
  • 如果构造函数调用未初始化具有静态或线程存储持续时间的对象,并且其初始值设定项中出现的每个完整表达式都是常量表达式。

  •   

任何其他初始化(即使是全局变量)都是动态初始化。但是,允许编译器将动态初始化视为静态初始化,前提是这样做不会改变程序的外部可见效果,假设它可以找出正确的值(即使该值不是官方有资格作为常数表达式。)

constant expression的定义(不幸的是)相当长且涉及到。定义的基本样式是将core constant expression定义为任何表达式,除了那些拟合异常列表的表达式(不幸的是,这些表达式不仅仅是一页长,因此将其概括为快速且易于理解的内容很容易)。

答案 2 :(得分:4)

静态初始化是一些带有编译时值的变量的初始化,这样该值最终被“烘焙”到可执行映像中(没有代码需要实际运行):

struct Foo {
  int x;
  int y;
};

Foo foo = { 0, 1 };

在上面的示例中,struct Foo是POD,因此编译器知道它的内存布局只是彼此相邻的两个整数。它还知道foo.x应初始化为0foo.y1。这足以产生一个“记忆图像”,显示foo在编译时应该看起来如何 并将其写入可执行图像。

当稍后运行映像时,OS加载程序将其内容映射到内存地址,这样使foo“活动”。重要的是foo的“初始化”实际上已经在进程之前完成(包括你的代码以及来自C / C ++运行时的代码,它们首先运行)有时间执行一个单独的CPU指令。

答案 3 :(得分:-1)

  

静态成员初始化发生在类范围内。因此,他们可以访问其他成员数据或功能。

引自MSDN

有一个很好的例子说明它是如何运作的。