有效地将数组的一部分设置为零



我正在尝试将一个简单对象数组重置为零,如下所示:

using Node = std::array<std::uint16_t, 256>;
using Array = std::array<Node, 4096>;
void reset_1(Array& a) {
std::fill(std::begin(a), std::end(a), Node{});
}

void reset_2(Array& a) {
a = {};
}
void reset_3(Array& a) {
a.fill(Node{});
}

所有这些函数都完成了任务,但查看编译器资源管理器(同时使用Clang 10.0.1和gcc 10.2(,reset_2在一个memset中完成,而其他两个在多个块中完成(使用std::fill_n的结果相同(。

在我的实际情况中,我实际上想要重置除第一个节点之外的所有节点。这会让我写一些类似的东西:

void reset_not_zero_1(Array& a) {
std::fill(std::begin(a) + 1, std::end(a), Node{});
}

void reset_not_zero_2(Array& a) {
std::memset(a.data() + 1, 0, sizeof(a) - sizeof(Node));
}

我的问题是:我是否用reset_not_zero_2调用了某种未定义的行为?这个数组的可复制性很差,但也许我遗漏了什么。

来自cppreference

将值ch转换为无符号字符,并将其复制到dest指向的对象的第一个计数字符。如果对象是一个潜在的重叠子对象或不是TriviallyCopy(例如,标量、C兼容结构或可普通复制的数组类型(,则行为未定义。如果计数大于的大小dest指向的对象,则行为未定义。

到目前为止还不错。

假设另一个节点大小为14,但其对齐为16

using Array = std::array<Node, 4096>;

"a"的大小将为16*4096=65536,因为Node将强制填充2。

std::memset(a.data() + 1, 0, sizeof(a) - sizeof(Node));

这将是65536-16字节中的65536-14个字节,这是不好的,因为它覆盖了下一个数据的2个字节。

另一方面,如果

sizeof(a) == a.size()*sizeof(a::value_type) 

那应该没问题。

此外,如果对准器强制更大尺寸,也应该可以。

我的问题是:我是否用reset_not_zero_2调用了某种未定义的行为?

否。我觉得不错。

相关内容

最新更新