Zero-инициализация элемента данных массива в конструкторе

у меня есть массив объектов класса, и внутри объекта класса у меня есть другой массив, который мне нужно будет инициализировать для всех нулей. Код компилируется и запускается, но мой вывод показывает с а не 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", как ожидалось.

6 ответов


просто использовать инициализация значением в списке инициализации конструктора. Это идиоматический способ сделать это на C++.

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

обратите внимание, что C++11 также допускает этот синтаксис:

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

в случае, если вам интересно почему это работает, из стандарта C++ 11 (обратите внимание, это также относится к C++03):

C++11 § 8.5, p10

объект, инициализатором которого является пустой набор скобок, т. е. (), должно быть значение инициализации.

этот термин значение инициализации переносит нас в:

C++11 § 8.5, p7

значение-инициализировать объект типа T означает:

  • Если T является (возможно в CV-квалифицированный) тип класс9 С предоставленным пользователем конструктор (12.1), то конструктор по умолчанию для T называется (и инициализация плохо сформированной, если T имеет никакого доступного конструктора по умолчанию);

  • Если T является (возможно, CV-квалифицированным) типом класса non-union без предоставленного пользователем конструктора, то объект инициализируется нулем и, если конструктор по умолчанию t неявно объявлен нетривиальным, этот конструктор вызывается.

  • если T-тип массива, то каждый элемент инициализируется значением;

  • в противном случае объект инициализируется нулем.

третий вариант в этом задействует инициализацию значения каждого элемента; четвертый применяется, как только мы доберемся до каждого из этих элементов, потому что они (a) не имеют типов классов, поэтому (1) и (2) ушли, и (b) не массивы, поэтому (3) ушел. Это оставляет только последний, и ваши элементы инициализируются нулем.


на Cache конструктор, когда вы делаете :

byte[16]={0};

вы только 16-го байта массива (который запрещен, поэтому эта операция имеет неопределенное поведение). Объекты массива инициализируются по умолчанию в C++, потому что вы храните int, инициализация не выполняется.

можно использовать std::fill инициализировать его :

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

или вы можете использовать обычный for-loop над вашим массивом.


memset-самое простое решение.

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

Вы делаете это неправильно на многих уровнях. Синтаксис, который вы используете, не делает того, что вы думаете. То, что вы делаете сейчас, по существу инициализирует 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-типом, что в этом контексте означает, что он может быть инициализирован via memset и поставить 0 для всей таблицы. Если T не поддерживает его, то для каждого элемента эквивалент element = 0 будет называться. Также проверка может быть оценена во время компиляции, поэтому, скорее всего,if будет скомпилирован, и для каждого типа во время компиляции будет создана простая "однострочная" версия.

вы можете вызвать его через:

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

есть две проблемы с вашим кодом:

byte[16]={0};

массива 0 на основе индекса, поэтому максимальный индекс в этом случае может быть 15, а не 16. Вы не развращает памяти.

во-вторых, вы должны пройти через все элементы и инициализировать их. Способ инициализации будет выполнен только для одного элемента.

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

инициализация массива с {0} работает только при объявлении массива.

вам нужен цикл for внутри конструктора, который устанавливает элементы массива в ноль.