在性能方面,使用memcpy更好还是使用std::copy()更好?为什么?

char *bits = NULL;
...

bits = new (std::nothrow) char[((int *) copyMe->bits)[0]];
if (bits == NULL)
{
    cout << "ERROR Not enough memory.\n";
    exit(1);
}

memcpy (bits, copyMe->bits, ((int *) copyMe->bits)[0]);

当前回答

如果你真的需要最大的复制性能(你可能不需要),这两个都不要用。

可以做很多事情来优化内存复制——如果你愿意使用多个线程/内核的话,甚至可以做得更多。例如:

在这个memcpy实现中缺少什么/不是最优的?

问题和一些答案都建议了实现或实现的链接。

其他回答

始终使用std::copy,因为memcpy仅限于c风格的POD结构,如果目标实际上是POD,编译器可能会用memcpy替换对std::copy的调用。

另外,std::copy可以用于许多迭代器类型,而不仅仅是指针。Std::copy更灵活,没有性能损失,是明显的赢家。

我的原则很简单。如果你正在使用c++,更喜欢c++库而不是C:)

只是一个小小的补充:memcpy()和std::copy()之间的速度差异可能会根据是否启用或禁用优化而有所不同。在g++ 6.2.0和没有优化的情况下,memcpy()明显胜出:

Benchmark             Time           CPU Iterations
---------------------------------------------------
bm_memcpy            17 ns         17 ns   40867738
bm_stdcopy           62 ns         62 ns   11176219
bm_stdcopy_n         72 ns         72 ns    9481749

当启用优化时(-O3),一切看起来几乎相同:

Benchmark             Time           CPU Iterations
---------------------------------------------------
bm_memcpy             3 ns          3 ns  274527617
bm_stdcopy            3 ns          3 ns  272663990
bm_stdcopy_n          3 ns          3 ns  274732792

数组越大,效果就越不明显,但即使在N=1000时,memcpy()在没有启用优化的情况下,速度也大约是前者的两倍。

源代码(需要谷歌基准):

#include <string.h>
#include <algorithm>
#include <vector>
#include <benchmark/benchmark.h>

constexpr int N = 10;

void bm_memcpy(benchmark::State& state)
{
  std::vector<int> a(N);
  std::vector<int> r(N);

  while (state.KeepRunning())
  {
    memcpy(r.data(), a.data(), N * sizeof(int));
  }
}

void bm_stdcopy(benchmark::State& state)
{
  std::vector<int> a(N);
  std::vector<int> r(N);

  while (state.KeepRunning())
  {
    std::copy(a.begin(), a.end(), r.begin());
  }
}

void bm_stdcopy_n(benchmark::State& state)
{
  std::vector<int> a(N);
  std::vector<int> r(N);

  while (state.KeepRunning())
  {
    std::copy_n(a.begin(), N, r.begin());
  }
}

BENCHMARK(bm_memcpy);
BENCHMARK(bm_stdcopy);
BENCHMARK(bm_stdcopy_n);

BENCHMARK_MAIN()

/* EOF */

理论上,memcpy可能具有微小的、难以察觉的、无限小的性能优势,只是因为它没有与std::copy相同的要求。从memcpy的手册页:

为避免溢出,请设置 由目标指向的数组 而源参数,应在 至少num字节,并且不应该 重叠(用于重叠内存 块,memmove是一个更安全的方法)。

换句话说,memcpy可以忽略数据重叠的可能性。(将重叠数组传递给memcpy是未定义的行为。)因此,memcpy不需要显式地检查这个条件,而std::copy可以使用,只要OutputIterator参数不在源范围内。注意,这并不是说源范围和目标范围不能重叠。

因此,由于std::copy有一些不同的要求,理论上它应该稍微慢一点(特别强调稍微慢一点),因为它可能会检查重叠的c数组,或者将c数组的复制委托给需要执行检查的memmove。但在实践中,您(和大多数分析人员)甚至可能察觉不到任何差异。

当然,如果不使用pod,无论如何也不能使用memcpy。

我所知道的所有编译器都会在适当的时候用memcpy替换一个简单的std::copy,或者更好的是,将拷贝向矢量化,这样它会比memcpy更快。

在任何情况下:侧写和找出自己。不同的编译器会做不同的事情,它很可能不会完全按照你的要求去做。

请参阅编译器优化的介绍(pdf)。

下面是GCC对POD类型的简单std::拷贝所做的工作。

#include <algorithm>

struct foo
{
  int x, y;    
};

void bar(foo* a, foo* b, size_t n)
{
  std::copy(a, a + n, b);
}

下面是反汇编(只有-O优化),显示了对memmove的调用:

bar(foo*, foo*, unsigned long):
    salq    $3, %rdx
    sarq    $3, %rdx
    testq   %rdx, %rdx
    je  .L5
    subq    $8, %rsp
    movq    %rsi, %rax
    salq    $3, %rdx
    movq    %rdi, %rsi
    movq    %rax, %rdi
    call    memmove
    addq    $8, %rsp
.L5:
    rep
    ret

如果将函数签名更改为

void bar(foo* __restrict a, foo* __restrict b, size_t n)

然后memmove变成memcpy,以实现轻微的性能改进。注意,memcpy本身将被大量向量化。