在构造函数中零初始化数组数据成员

Zero-initializing an array data member in a constructor

本文关键字:数组 数据成员 初始化 构造函数      更新时间:2023-10-16

我有一个类对象数组,在类对象中我有另一个数组,我需要将其初始化为全零。代码编译并运行,但我的输出显示的是C而不是0.

从头文件:

class Cache {
private:
    int byte[16];
public:
    Cache();
    int getBytes(int);
    ~Cache();
};

从cpp文件

Cache::Cache()  
{
    byte[16]={0};
}
int Cache::getBytes(int j){
    return byte[j];
}

从另一个CPP文件

for (int i = 0; i < 16; i++) 
{
    for (int j = 0; j < 16; j++)  //visual check of initializes main memory
    {
        cout << cache[i].getBytes(j) << " ";
}
}

设置正确吗?如前所述,getBytes返回'C'而不是'0'。

只需在构造函数初始化列表中使用值初始化。这是c++中惯用的方法。

Cache::Cache() : byte()
{ 
}

注意c++ 11也允许这种语法:

Cache::Cache() : byte{}
{ 
}

如果你想知道为什么可以工作,从c++ 11标准(注意这也适用于c++ 03):

c++ 11§8.5,

初始化式为圆括号的空集合的对象,即(),应value-initialized

术语value-initialized带我们到:

c++ 11§8.5,

对T类型的对象进行值初始化意味着:

  • 如果T是一个(可能是cv限定的)类类型9具有用户提供的构造函数(12.1),则调用T的默认构造函数(如果T没有可访问的默认构造函数,则初始化是病态的);

  • 如果T是一个(可能是cv限定的)非联合类类型,没有用户提供的构造函数,则对象为零初始化,如果T的隐式声明的默认构造函数是非平凡的,则调用该构造函数。

  • 如果T是数组类型,则每个元素都进行值初始化;

  • ,否则为零初始化

第三个选项触发每个元素的值初始化;第四个应用于每个元素,因为它们(a)没有类类型,所以(1)和(2)没有了,(b)不是数组,所以(3)没有了。这样就只剩下最后一个元素,并且元素都是零初始化的。

Cache构造函数中,当您这样做时:

byte[16]={0};

你只设置了数组的第16个字节(这是越界的,所以这个操作有未定义的行为)。数组对象在c++中是默认初始化的,因为您存储int,所以不执行初始化。

你可以使用std::fill来初始化它:

Cache::Cache()  
{
  std::fill(byte, byte+16, 0);
}

你在很多层面上都做错了。您使用的语法并不像您想象的那样。您现在所做的实际上是将表的第17个元素初始化为0。

在您的情况下,memset可能是最快和最简单的。但是,它不适用于复杂类型,因此我会考虑为一般情况编写一个简单的代码片段,例如:

template<typename T>
inline void zero_init(T array[], size_t elements){
 if( std::is_pod<T>() ) memset(array, 0, sizeof(T)*elements);
 else std::fill(begin(array), begin(array)+elements, 0);
}

这将检查类型是否为pod类型,这在上下文中意味着它可以通过memset初始化,并将整个表的0初始化。如果T不支持,则对每个元素调用一个等价的element = 0。此外,检查也可能在编译时进行评估,因此最有可能的是if将被编译掉,并且在编译时为每种类型创建一个简单的"单行"版本。

你可以通过:

Cache::Cache()  
{
  zero_init(byte, 16);
}

你的代码有两个问题:

byte[16]={0};

Array有基于0的索引,所以在这种情况下最大索引可以是15,而不是16。你正在破坏内存。

其次,必须遍历所有元素并初始化它们。你的初始化方式将只针对一个元素。

Cache::Cache()  
{
  for(int i=0;i<16;i++)
   byte[i]=0;
}

memset是最简单的解决方案。

Cache::Cache()  
{
  memset(byte, 0, sizeof(byte));
}

c++ 11支持这种语法:

#include <iostream>
using namespace std;
class Test
{
private:
   int bytes[16] = {};
   
public:
   void print()
   {
      for(int i = 0; i < 16; i++)
      {
         cout << bytes[i] << " ";
      }
      cout << endl;
   }
};
int main()
{
   Test test;
   test.print();
}

基本上使用零初始化和默认成员初始化器(默认构造函数)