【问题标题】:fill_n vs memset to set default value of an arrayfill_n vs memset 设置数组的默认值
【发布时间】:2021-05-21 23:45:19
【问题描述】:

如果你想用默认值 n 填充数组,我想知道什么是理想的方法:

#include <cstring> // for memset
#include <algorithm> // for fill_n

static constexpr int N = 100;
int a[N];
static constexpr int defaultValue = -1;

void* memset( void* dest, int ch, std::size_t count );

memset(a, defaultValue, sizeof(a));

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

constexpr OutputIt fill_n( OutputIt first, Size count, const T&amp; value );

fill_n(a, N, defaultValue);

(fill_n) 如果 count > 0,则将给定值分配给从 first 开始的范围内的第一个 count 元素。否则不执行任何操作。

我正在寻找见解,我当然知道如何阅读文档!

编辑:defaultValue 可能不仅仅是-1。

【问题讨论】:

  • 对于普通类型,fill_n 可能会导致类似memset 的操作,而对于其他类型,memset 将无法将对象复制到位。我会坚持使用fill_n。两者都适用。
  • 取决于你真正想做什么。 memset 作用于字节,因此-1 被写入ints 数组中的每个字节。使用 -1 也可以,因为 -1 的 4 个字节与设置为 -1 的 int 具有相同的位模式。尝试使用 1,假设 32 位 int,您将得到一个包含 16843009 (0x01010101) 的数组。
  • 关于编辑和我上面的评论,如果您希望数组中的每个int 都将defaultValue 作为默认值,那么听起来fill_n 是唯一的选择。还要考虑如果defaultValue 太大而无法放入单个字节怎么办。 memset 在这种情况下完全没用,因为它将给定的值降低到 unsigned char..
  • 您的观点很有趣,您可以将其添加到您的(正式)答案中

标签: c++ memset


【解决方案1】:

这两个函数做不同的事情。当然,它们会填充一块内存,但它们的处理方式完全不同。

memset 在字节级别运行。 defaultValue 被破解为unsigned char,因此大于单个字节大小的defaultValue 会被缩减为大小并且信息会丢失。现在字节大小的值单独应用于每个字节,而不是数组中的每个int。在 -1 的情况下,您会得到“幸运”,因为 0xFF 的四个字节看起来相同,即 0xFFFFFFFF,作为 32 位整数世界中的二进制补码 -1。大多数其他数字没有这样的运气。例如,1 不会导致一个充满 int 的数组设置为 1,而是用 0x01010101 或 16843009 填充。

fill_n 另一方面,尊重数组元素的类型。数组中的每个int 都将设置为defaultValue。在 defaultValue 为 1 的情况下,数组将充满 1。 defaultValue of 256,提供了一个完整的 256 数组。

就速度而言,这可能并不重要。如今,以字节为单位读取或写入的内存已很少见。一次写入整个ints 可能会更快。但是一个好的memset 实现知道这一点并将利用它。如果没有,编译器可能会。

【讨论】:

    猜你喜欢
    • 2011-05-14
    • 1970-01-01
    • 2012-08-27
    • 2018-08-29
    • 1970-01-01
    • 2014-02-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多