我正在尝试将一个简单对象数组重置为零,如下所示:
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调用了某种未定义的行为?
否。我觉得不错。