代码之家  ›  专栏  ›  技术社区  ›  Roddy

C++ POD类型何时初始化为零?

  •  15
  • Roddy  · 技术社区  · 14 年前

    从C背景来看,我一直假设POD类型(例如,int型)在C++中从不自动初始化,但这显然是错误的!

    我的理解是,只有“裸”的非静态POD值不会被填充为零,如代码片段所示。我说得对吗?还有其他重要的事情我错过了吗?

    static int a;
    
    struct Foo { int a;};
    
    void test()
    {
      int b;     
      Foo f;
      int *c = new(int); 
      std::vector<int> d(1);
    
      // At this point...
      // a is zero
      // f.a is zero
      // *c is zero
      // d[0] is zero
      // ... BUT ... b is undefined     
    }  
    
    5 回复  |  直到 14 年前
        1
  •  17
  •   James McNellis    14 年前

    假设你没有修改 a 打电话之前 test() , 值为零,因为静态存储持续时间的对象在程序启动时初始化为零。

    d[0] 值为零,因为由调用的构造函数 std::vector<int> d(1) 第二个参数采用默认参数;第二个参数复制到所构造向量的所有元素中。默认参数是 T() ,因此您的代码相当于:

    std::vector<int> d(1, int());
    

    你说得对 b 具有不确定的值。

    f.a *c 两者都有不确定的值。To value initialize them (which for POD types is the same as zero initialization), you can use:

    Foo f = Foo();      // You could also use Foo f((Foo()))
    int* c = new int(); // Note the parentheses
    
        2
  •  1
  •   utnapistim    14 年前

    Actually some of the values being zero may be due to you trying this code in the debug version of the application (if that is the case).

    如果我没有弄错,在你的代码中:

    • a应未初始化。
    • B应未初始化
    • C应该指向一个新的(未初始化的)int
    • d应初始化为[0](如您正确猜测的那样)
        3
  •  1
  •   Jeremy Bell    14 年前

    请注意,操作系统作为安全功能完成的零初始化通常只在第一次分配内存时完成。我指的是堆、堆栈和数据段中的任何段。堆栈和数据部分的大小通常是固定的,并且在应用程序加载到内存中时进行初始化。

    数据段(包含静态/全局数据和代码)通常不会得到“重用”,尽管如果在运行时动态加载代码,情况可能不会如此。

    堆栈段中的内存将一直重复使用。局部变量、函数堆栈帧等。它们都在不断地被使用和重复使用,并且不是每次都初始化——只是在首次加载应用程序时。

    但是,当应用程序请求堆内存时,内存管理器通常会在授予请求之前将内存段初始化为零,但只对新的段进行初始化。如果您请求堆内存,并且已经初始化的段中有可用空间,则不会再次进行初始化。因此,不能保证如果应用程序重新使用特定内存段,它将再次初始化为零。

    因此,例如,如果在堆上分配一个foo,给它的字段赋值,删除foo实例,然后在堆上创建一个新foo,那么新foo有可能被分配到与旧foo相同的内存位置,因此它的字段最初的值与旧foo的字段相同。

    如果您考虑一下,这是有意义的,因为操作系统只是初始化数据以防止一个应用程序从另一个应用程序访问数据。允许应用程序访问其自己的数据的风险较小,因此出于性能原因,并非每次都进行初始化—只是第一次将特定内存段提供给应用程序使用(在任何段中)。

    但是,有时在调试模式下运行应用程序时,某些调试模式运行时会在每次分配时初始化堆栈和堆数据(因此FOO字段将始终初始化)。但是,不同的调试运行时将数据初始化为不同的值。Some zero initialize, and some initialize to a "marker" value.

    关键是-永远不要在代码中的任何地方使用未初始化的值。绝对不能保证它们将被初始化为零。另外,请务必阅读前面链接的关于parens和default vs value初始化的文章,因为这会影响“未初始化”值的定义。

        4
  •  0
  •   slaphappy    14 年前

    对我来说,pod类型是根据所放置的内存部分初始化的。你的 static int a 在数据段上分配,因此在启动时具有默认值。但是,我认为在你的例子中f并不是不完整的…

        5
  •  0
  •   Alan    14 年前

    它们不会。调试位版本可能会这样做,但通常它只是放在内存中,并初始化为内存中的值。