我有一个类,该类包含较大的std :: array,如何初始化数组?
请参阅课程测试;
样本:
class context{......}
class value
{
public:
value(context& ctx) : ctx_(ctx){
}
protected:
context& ctx_;
int data_ = 0;
}
class test
{
public:
test() : /*i need to initialize values at here*/ values_{ctx_,.....}
{
}
protected:
context ctx_;
std::array<value_t,10000> values_;
}
实际上,这个数组可能只包含3或5个元素,而不是10000,但是有些人肯定会给我下面的答案
test() : values_{ctx_,ctx_,ctx_,ctx_,ctx_}
{
}
我不需要像上面那样尴尬的答案。
有没有一种方法可以使用简单的代码(如折叠表达式)来初始化std :: array?
答案 0 :(得分:1)
您可以委托给带有参数包的构造函数,然后将其折叠:
#include <utility>
#include <cstddef>
class test
{
public:
test() : test(std::make_index_sequence<10000>{}) {}
private:
template<std::size_t... I>
test(std::index_sequence<I...>) : values_{{(I, ctx_)...}} {}
protected:
context ctx_;
std::array<value_t, 10000> values_;
};
尽管对于我来说,在-O0
以外的任何优化级别上,这绝对是 killed 的编译时间(并且可能会破坏您编译的代码大小)
您也可以尝试构造到未初始化的内存中,因此您不需要默认构造:
#include <array>
#include <cstddef>
#include <new>
#include <memory>
class test
{
public:
test() {
std::byte* p = value_memory_;
for (std::byte* end = std::end(value_memory_); p < end; p += sizeof(value_t)) {
new (p) value_t(ctx_);
}
}
~test() {
value_t* values = get_values();
std::destroy(values, values + 10000);
}
protected:
context ctx_;
value_t* get_values() {
return std::launder(reinterpret_cast<value_t*>(value_memory_));
}
const value_t* get_values() const {
return std::launder(reinterpret_cast<const value_t*>(value_memory_));
}
// These are UB, but work on most compilers, and would generally be nicer
// to work with
value_t(&get_values())[10000] {
return *std::launder(reinterpret_cast<value_t(*)[10000]>(value_memory_));
}
const value_t(&get_values() const)[10000] {
return *std::launder(reinterpret_cast<const value_t(*)[10000]>(value_memory_));
}
private:
alignas(value_t) std::byte value_memory_[sizeof(value_t) * 10000u];
};
这将花费一些运行时成本,并且您必须丢掉std::array
(除非您要使用std::array<std::aligned_storage_t<sizeof(value_t), alignof(value_t)>, 10000>
,否则必须清洗数组的每个元素)
答案 1 :(得分:1)
问题是您的数组包含没有默认构造函数的类型的元素,因此当您声明拥有该类型的std::array
时,只能使用aggregate initialization初始化该数组,因此您可以将值显式传递给每个元素的构造函数。当数组是类或结构的成员时,该初始化需要使用类/结构构造函数的member initialization list。正是您要避免的事情。
要解决此问题,可以使用placement-new
显式地在循环中分别构造每个数组元素:
#include <type_traits>
class context{......}
class value
{
public:
value(context& ctx) : ctx_(ctx){
}
protected:
context& ctx_;
int data_ = 0;
}
class test
{
public:
test()
{
for (auto &v : values_)
new (&v) value(ctx_);
}
~test()
{
for (auto &v : values_) {
// note: needs std::launder in C++17 and later
// std::launder(reinterpret_cast<value*>(&v))->~value();
reinterpret_cast<value*>(&v)->~value();
}
}
protected:
context ctx_;
using storage_type = std::aligned_storage<sizeof(value), alignof(value)>::type;
std::array<storage_type, 10000> values_;
// Access an object in aligned storage
value& operator[](std::size_t pos)
{
// note: needs std::launder in C++17 and later
// return *std::launder(reinterpret_cast<value*>(&values_[pos]));
return *reinterpret_cast<value*>(&values_[pos]);
}
};
答案 2 :(得分:0)
您可以在数组上使用fill()方法: https://en.cppreference.com/w/cpp/container/array/fill