我试图将简单对象的数组重置为零,如下所示:

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

到现在为止还挺好。
假设另一个节点大小为14,但其alignas为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)
那应该没问题。
同样,如果将alignas强制使用更大的尺寸,也应该可以。

08-08 03:42