std::array 没有默认构造函数的对象的初始化?
std::array initialization, for objects without a default ctor?
我在一个内存受限的系统上工作,其中 new/malloc 调用被包装以在构建时失败。不幸的是,std::vector
不是一个可接受的解决方案。
我有一个 class 的 std::array
成员,其大小在编译时已知,但可能因特定目标(例如来自配置文件)而异,所以我可以访问类似constexpr size_t len = Config::ArrSize
。我希望我的 class 包含 std::array
个对象,但这些对象没有默认构造函数。我更愿意避免两步初始化(例如,实现一个无意义的默认构造函数,然后稍后将实际值传递给它们)。我也知道编译时的所有构造函数值!我只是找不到一种干净的方式来传达这一点,因为 length 可能因特定目标而异,但对于任何 given garget 都是已知的。
有没有办法清楚地传达这一点?例如我想要类似于
的东西
#include Config.h
constexpr size_t arr_size = Config::ArrSize;
constexpr size_t ctor_arg = Config::Arg;
class Foo {
public:
// line which doesn't work but demonstrates what I'd like
Foo() : fooArr {Bar(ctor_arg)} {}
private:
std::array<Bar, arr_size> fooArr;
};
它们都将以相同的方式初始化,并且在编译时具有已知的大小。由于缺少默认构造函数,它们必须在初始化时构造。类似于 std::fill
但在初始化时可用。是的,我可以用指针将它推迟一点,直到 ctor 主体,但恕我直言,这很丑陋。我该怎么做?
Bar
没有 constexper
构造函数,但也许这会有所帮助?
你可以这样做:
class Bar
{
public:
Bar(someClass obj) { /*...*/ }
};
class Foo
{
public:
template<class... T>
Foo(T... obj) : fooArr {Bar(obj)...} {}
private:
std::array<Bar, arr_size> fooArr;
}
虽然我不知道这是否是最好的方法。
选项 1:使用命名构造函数惯用语
我们将编写一个 named constructor idiom、array_repeat()
,它采用单个值并在 compile-time 处生成一个包含所有值的数组。然后你可以写:
class Foo {
public:
Foo() : fooArr {array_repeat<arr_size>(Bar(ctor_arg))} {}
private:
std::array<Bar, arr_size> fooArr;
};
我已将实现拆分为单独的问答,here on SO。
选项 2:使用带有自定义分配器的向量
std::vector
has 一个额外的模板参数 - 分配器 class。默认值是使用 new[]
和 delete[]
的分配器。但是 - 你可以有一个分配器占用堆栈上的固定缓冲区(或任何地方),并仍然使用可调整大小的 std::vector
。这将使您无需 pre-construct 虚拟值。
您可以使用大括号初始化 std::array<int,4> a = {1,2,3,4};
...也许您可以编写一个模板函数来初始化它而不直接编写初始化列表,但我不确定如何。
一般来说,当类型不可默认构造时,我不建议使用 std::array
。您可以使用像 boost::small_vector
这样具有静态容量和动态大小的类型。
我在一个内存受限的系统上工作,其中 new/malloc 调用被包装以在构建时失败。不幸的是,std::vector
不是一个可接受的解决方案。
我有一个 class 的 std::array
成员,其大小在编译时已知,但可能因特定目标(例如来自配置文件)而异,所以我可以访问类似constexpr size_t len = Config::ArrSize
。我希望我的 class 包含 std::array
个对象,但这些对象没有默认构造函数。我更愿意避免两步初始化(例如,实现一个无意义的默认构造函数,然后稍后将实际值传递给它们)。我也知道编译时的所有构造函数值!我只是找不到一种干净的方式来传达这一点,因为 length 可能因特定目标而异,但对于任何 given garget 都是已知的。
有没有办法清楚地传达这一点?例如我想要类似于
的东西#include Config.h
constexpr size_t arr_size = Config::ArrSize;
constexpr size_t ctor_arg = Config::Arg;
class Foo {
public:
// line which doesn't work but demonstrates what I'd like
Foo() : fooArr {Bar(ctor_arg)} {}
private:
std::array<Bar, arr_size> fooArr;
};
它们都将以相同的方式初始化,并且在编译时具有已知的大小。由于缺少默认构造函数,它们必须在初始化时构造。类似于 std::fill
但在初始化时可用。是的,我可以用指针将它推迟一点,直到 ctor 主体,但恕我直言,这很丑陋。我该怎么做?
Bar
没有 constexper
构造函数,但也许这会有所帮助?
你可以这样做:
class Bar
{
public:
Bar(someClass obj) { /*...*/ }
};
class Foo
{
public:
template<class... T>
Foo(T... obj) : fooArr {Bar(obj)...} {}
private:
std::array<Bar, arr_size> fooArr;
}
虽然我不知道这是否是最好的方法。
选项 1:使用命名构造函数惯用语
我们将编写一个 named constructor idiom、array_repeat()
,它采用单个值并在 compile-time 处生成一个包含所有值的数组。然后你可以写:
class Foo {
public:
Foo() : fooArr {array_repeat<arr_size>(Bar(ctor_arg))} {}
private:
std::array<Bar, arr_size> fooArr;
};
我已将实现拆分为单独的问答,here on SO。
选项 2:使用带有自定义分配器的向量
std::vector
has 一个额外的模板参数 - 分配器 class。默认值是使用 new[]
和 delete[]
的分配器。但是 - 你可以有一个分配器占用堆栈上的固定缓冲区(或任何地方),并仍然使用可调整大小的 std::vector
。这将使您无需 pre-construct 虚拟值。
您可以使用大括号初始化 std::array<int,4> a = {1,2,3,4};
...也许您可以编写一个模板函数来初始化它而不直接编写初始化列表,但我不确定如何。
一般来说,当类型不可默认构造时,我不建议使用 std::array
。您可以使用像 boost::small_vector
这样具有静态容量和动态大小的类型。