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 над вашим массивом.
Вы делаете это неправильно на многих уровнях. Синтаксис, который вы используете, не делает того, что вы думаете. То, что вы делаете сейчас, по существу инициализирует 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 внутри конструктора, который устанавливает элементы массива в ноль.