【发布时间】:2019-06-20 00:11:23
【问题描述】:
我想知道是否有合适的方法来做到这一点。
举个例子:
struct Test {
static std::array<unsigned, 123> data;
};
std::array<unsigned, 123> Test::data = {};
如果我想将 data 中的所有元素设置为某个值,例如 5。
我可以这样做:
struct Test {
static std::array<unsigned, 123> data;
private:
static decltype(data) init_data_arr() {
decltype(data) arr = {};
arr.fill(5);
return arr;
}
};
std::array<unsigned, 123> Test::data = Test::init_data_arr();
但是我会分配一个额外的内存数组并对其进行复制,这似乎并不理想。
另一个不太占用内存的选项是这样的:
struct Test {
static bool is_init;
static std::array<unsigned, 123> data;
Test() {
if (!is_init) {
is_init = true;
data.fill(5);
}
}
};
bool Test::is_init = false;
std::array<unsigned, 123> Test::data = {};
但是现在我在构建我的 Test 结构时有额外的开销。
现在我知道您可以像这样初始化 pod 数组:std::array<int, 3> a = {1, 2, 3}; 但对于 N 大小的数组,这很快就会变得难以维护。
我似乎遇到的每个解决方案都只是在数组类上使用 fill 成员函数,但总是将数组视为非静态成员变量,或者它在 main 中初始化它们,这两者都不是真的帮助我的情况。
编辑: 我创建了这个实用程序头来概括第二个选项。 #pragma 一次
#include <utility>
#include <iterator>
#include <algorithm>
#include <type_traits>
namespace Utils {
template<typename Container>
using element_type_t = std::remove_reference_t<decltype(*std::begin(std::declval<Container&>()))>;
template<class Container>
static Container create_filled_container(const element_type_t<Container>& value) {
Container container = {};
std::fill(container.begin(), container.end(), std::move(value));
return container;
}
}
这可能会得到更多改进,但它似乎有效。用法如下:
std::array<unsigned, 123> Test::data = Utils::create_filled_container<decltype(data)>(456);
它将所有元素设置为您指定的任何内容。
编辑2: 所以我做了一些更多的测试,看起来调用一个函数来填充数组与手动执行它并不总是产生相同的程序集。
我已经设置了一个演示 here!
编辑3: 改变了一些东西,所以它可能是 constexpr,这是它的当前形式:
template<class Container>
static constexpr Container create_filled_container(const element_type_t<Container>& value) {
Container container = {};
for (auto it = container.begin(); it != container.end(); ++it)
*it = value;
return container;
}
现在生成相同的程序集。
【问题讨论】:
-
但是我会分配一个额外的内存数组并对其进行复制,这似乎并不理想。 你确定吗? NRVO 将消除这一点,让您无需支付任何额外费用。您应该检查程序集,看看它是否这样做。
-
@NathanOliver 好电话,我在测试程序集生成时忘记打开优化。但你是对的,当 -O3 用于
Test::init_data_arr()示例与 {0, ..., n} 初始化时,它确实会产生相同的程序集。 -
@NathanOliver 那么你会说这可能是解决这个问题的最佳方式,还是有更优雅的解决方案?
-
我会这样做。它易于理解,易于维护,并且应该编译掉。代码完成后,如果您对性能不满意,请查看配置文件并查看问题所在。很可能不会是这样。
-
只需使用 constexpr 函数对其进行初始化。没有运行时代码。
标签: c++ arrays static-members array-initialization