C++ 值初始化自定义容器的项目
C++ value initialize items of a custom container
让我们以自定义 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
。请给我一些提示。
就这么简单
for (int i = 0; i < _size; i++)
_buff[i] = Object{};
或者,您可以摆脱循环并在此处添加一对 {}
(或 ()
):
_buff = new Object[_capasity]{};
// ^^
但此选项将值初始化所有 _capasity
个对象,而不是第一个 _size
个对象,如 所述。
此外,请注意,如果您想模仿 std::vector
的行为,您需要分配原始存储(可能 std::aligned_storage
)并手动调用构造函数(通过 placement-new)和析构函数。
如果 Object
是 class 类型,_buff = new Object[_capasity];
为所有 _capasity
对象调用默认构造函数,而不是为前 _size
个对象调用默认构造函数,因为 std::vector
确实如此。
调用时注意
_buff = new Object[_capasity];
(顺便说一句,为什么你把这个初始化从 init-list 移到构造函数体中?)你已经有默认初始化的 _capasity
对象。默认初始化在这里具有以下效果:虽然标量类型的元素将保持未初始化状态(并从 UB 中读取),但对于 class 类型,您已经调用了 _capasity
构造函数。
为了避免不必要的构造,您有以下可能的选择,其中包括:
使用std::aligned_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
}
再次记住当 vector 增长时 buff_
应该被 aligned_alloc
ed(对于普通类型可以 std::realloc()
ed),并且在析构函数中它应该是 std::free()
d — 在此之前,应该销毁其中的 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[]
d之后。
让我们以自定义 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
。请给我一些提示。
就这么简单
for (int i = 0; i < _size; i++)
_buff[i] = Object{};
或者,您可以摆脱循环并在此处添加一对 {}
(或 ()
):
_buff = new Object[_capasity]{};
// ^^
但此选项将值初始化所有 _capasity
个对象,而不是第一个 _size
个对象,如
此外,请注意,如果您想模仿 std::vector
的行为,您需要分配原始存储(可能 std::aligned_storage
)并手动调用构造函数(通过 placement-new)和析构函数。
如果 Object
是 class 类型,_buff = new Object[_capasity];
为所有 _capasity
对象调用默认构造函数,而不是为前 _size
个对象调用默认构造函数,因为 std::vector
确实如此。
调用时注意
_buff = new Object[_capasity];
(顺便说一句,为什么你把这个初始化从 init-list 移到构造函数体中?)你已经有默认初始化的 _capasity
对象。默认初始化在这里具有以下效果:虽然标量类型的元素将保持未初始化状态(并从 UB 中读取),但对于 class 类型,您已经调用了 _capasity
构造函数。
为了避免不必要的构造,您有以下可能的选择,其中包括:
使用std::aligned_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 }
再次记住当 vector 增长时
buff_
应该被aligned_alloc
ed(对于普通类型可以std::realloc()
ed),并且在析构函数中它应该是std::free()
d — 在此之前,应该销毁其中的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[]
d之后。