【问题标题】:What performance can I expect from std::fill_n(ptr, n, 0) relative to memset?相对于 memset,我可以从 std::fill_n(ptr, n, 0) 获得什么性能?
【发布时间】:2017-05-07 05:51:17
【问题描述】:

对于作为指针的迭代器ptrstd::fill_n(ptr, n, 0) 应该与memset(ptr, 0, n * sizeof(*ptr)) 执行相同的操作(但请参阅@KeithThompson 对this answer 的评论)。

对于 C++11/C++14/C++17 模式下的 C++ 编译器,在哪些条件下可以期望它们编译为相同的代码?并且当/如果它们不编译为相同的代码时,-O0 是否存在显着的性能差异? -O3?

注意:当然,部分/大部分答案可能是特定于编译器的。我只对一两个特定的编译器感兴趣,但请写下你知道答案的编译器。

【问题讨论】:

  • FWIW MSVS 使用模板魔法来确定它是否可以在容器内使用 memset 和 memcpy。不确定算法是否也以这种方式实施,但认为他们会这样做并不是一个飞跃。也就是说,以两种方式编码和衡量。这会给你最好的答案。
  • @ChrisBeck:见编辑。
  • @NathanOliver:好的,但是 - memset 也是一个需要以某种方式实现的功能。
  • 空指针不一定都是 0 位。我不确定标准对浮点类型的要求,但我认为那里的情况相同。即std::fill_n,它用逻辑空值填充,一般情况下与memset不一样。
  • 根据我的经验,大多数优化器 足够聪明,可以识别 for 循环或标准算法等效于编译器内在函数/__builtins 之一,并生成相同的代码.除非代码被分析器捕获,否则我不会打扰。

标签: c++ c++11 memory c++-standard-library memset


【解决方案1】:

对于所有适合 memset 的场景(即所有对象都是 POD),您很可能会发现在启用任何级别的优化时这两个语句是等效的。

对于不适合memset 的场景,比较没有实际意义,因为使用memset 会导致程序不正确。

您可以使用 Godbolt(以及许多其他工具)等工具轻松检查自己:

例如,在 gcc6.2 上,这两个函数生成完全相同的代码,优化级别为 -O3:

#include <algorithm>
#include <cstring>

__attribute__((noinline))
  void test1(int (&x) [100])
{
  std::fill_n(&x[0], 100, 0);
}

__attribute__((noinline))
  void test2(int (&x) [100])
{
  std::memset(&x[0], 0, 100 * sizeof(int));
}

int main()
{
  int x[100];
  test1(x);
  test2(x);
}

https://godbolt.org/g/JIwI5l

【讨论】:

  • 使用 Godbolt 比较为不同版本的函数生成的汇编代码的不错的快速技术。谢谢!
【解决方案2】:

答案取决于您对标准库的实现。

例如,MSVC 有多个 std::fill_n 的实现,具体取决于您要填充的类型。

使用char*signed char*unsigned char* 调用std::fill_n,它将直接调用memset 来填充数组。

inline char *_Fill_n(char *_Dest, size_t _Count, char _Val)
{   // copy char _Val _Count times through [_Dest, ...)
_CSTD memset(_Dest, _Val, _Count);
return (_Dest + _Count);
}

如果你用另一种类型调用,它会填充一个循环:

template<class _OutIt,
class _Diff,
class _Ty> inline
_OutIt _Fill_n(_OutIt _Dest, _Diff _Count, const _Ty& _Val)
{   // copy _Val _Count times through [_Dest, ...)
for (; 0 < _Count; --_Count, (void)++_Dest)
    *_Dest = _Val;
return (_Dest);
}

确定特定编译器和标准库实现开销的最佳方法是使用这两个调用来分析代码。

【讨论】:

    猜你喜欢
    • 2021-11-11
    • 2011-06-03
    • 1970-01-01
    • 2021-12-10
    • 2012-04-10
    • 2021-05-16
    • 1970-01-01
    • 2012-06-04
    • 2014-08-31
    相关资源
    最近更新 更多