Значение C++ инициализирует элементы пользовательского контейнера
Давайте возьмем на заказ vector
реализация в качестве примера:
template<typename Object>
class myVector {
public:
explicit myVector(int size = 0) :
_size{ size },
_capasity{ size + SPARE_CAPACITY }
{
_buff = new Object[_capasity];
if (_size > 0) {
for (int i = 0; i < _size; i++) {
//_buff[i] = 0;
}
}
}
// more code
private:
Object * _buff = nullptr;
int _size;
int _capasity;
};
Итак, мой вопрос, как сделать myVector
быть инициализированным значением в случае, если я инициализирую его как:
int main() {
myVector<int> v02(5);
}
Здесь содержится 5 int
значения, поэтому мне нужно, чтобы это было все нули; то же самое с другими типами. Я закомментировал _buff[i] = 0;
как это конкретно для int
, Пожалуйста, дайте мне несколько советов.
2 ответа
Это так просто, как
for (int i = 0; i < _size; i++)
_buff[i] = Object{};
Кроме того, вы можете избавиться от цикла и добавить пару {}
(или же ()
) Вот:
_buff = new Object[_capasity]{};
// ^^
Но эта опция будет инициализировать все значения _capasity
объекты, а не первый _size
те, как отмечено @bipll.
Также обратите внимание, что если вы хотите имитировать поведение std::vector
нужно выделить сырой сток (возможно std::aligned_storage
) и вызывать конструкторы (посредством размещения новых) и деструкторы вручную.
Если Object
это тип класса, _buff = new Object[_capasity];
вызывает конструкторы по умолчанию для всех _capasity
объекты, а не для первого _size
объекты как std::vector
делает.
Обратите внимание, что при звонке
_buff = new Object[_capasity];
(кстати, почему вы переместили эту инициализацию из списка инициализации в тело конструктора?) у вас уже есть инициализация по умолчанию _capasity
объекты. Инициализация по умолчанию имеет следующие эффекты: хотя элементы скалярного типа остаются неинициализированными (и читают из них UB), для типов классов, которые вы уже вызвали _capasity
Конструкторы.
Чтобы избежать ненужных конструкций, у вас есть следующие возможные варианты, среди прочего:
Используйте std::align_alloc для выделения неинициализированной памяти:
explicit myVector(std::size_t size = 0) : size_{ size } , capacity_{ size + SPARE_CAPACITY } , buff_{std::aligned_alloc(alignof(Object), _capacity)} { if(!buff_) throw std::bad_alloc(); if(size) new (buff_) Object[size]{}; // empty braces answer your original query }
Помни это снова
buff_
должно бытьaligned_alloc
ред, когда вектор растет (может бытьstd::realloc()
для тривиальных типов), а в деструкторе это должно бытьstd::free()
г - и до этогоsize_
объекты внутри него должны быть уничтожены (с явным вызовом~Object()
).+ Изменить
buff_
Тип для чего-то более тривиального, но правильно выровненного:using Storage = std::aligned_storage_t<sizeof(Object), alignof(Object)>; Storage *buff_; Object *data_ = nullptr; public: explicit myVector(std::size_t size = 0) : size_{ size } , capacity_{ size + SPARE_CAPACITY } , buff_{new Storage(_capacity)} { if(size) data_ = new (buff_) Object[size]{}; }
Опять же, в деструкторе объекты должны быть уничтожены вручную, но на этот раз
buff_
может быть простоdelete[]
г потом.