c++ 为什么std::copy比std::string构造函数快?

qfe3c7zg  于 2023-08-09  发布在  其他
关注(0)|答案(1)|浏览(128)

我尝试了这些代码,来比较std::copystd::string的构造函数。

#include <chrono>
#include <iostream>
#include <vector>

void construct_test() {
  std::vector<uint8_t> raw_data;
  for (int i = 0; i < 1000 * 1024; i++) {
    raw_data.push_back(i % 256);
  }

  auto start = std::chrono::high_resolution_clock::now();
  std::string target_data;
  target_data = std::string(raw_data.begin(), raw_data.end());
  auto finish = std::chrono::high_resolution_clock::now();
  std::cout << "construct: " << std::chrono::duration_cast<std::chrono::microseconds>(finish -
                                                                     start)
                   .count()
            << "us" << std::endl;
}

void copy_test() {
  std::vector<uint8_t> raw_data;
  for (int i = 0; i < 1000 * 1024; i++) {
    raw_data.push_back(i % 256);
  }

  auto start = std::chrono::high_resolution_clock::now();
  std::string target_data;
  target_data.resize(raw_data.size());
  std::copy(raw_data.begin(), raw_data.end(), target_data.begin());
  auto finish = std::chrono::high_resolution_clock::now();
  std::cout << "copy: " << std::chrono::duration_cast<std::chrono::microseconds>(finish -
                                                                     start)
                   .count()
            << "us" << std::endl;
}

int main() {
  construct_test();
  copy_test();

  return 0;
}

字符串
我得到的结果是:

construct: 6245us
copy: 1087us


std::copy的速度提升6倍!
这是符合预期的吗?如果是,原因是什么?
我搜索了很多将向量转换为字符串的方法,但没有人提到std::copy的方法。我应该用这种方式吗?有什么缺点吗?

r3i60tvu

r3i60tvu1#

正如评论者所指出的,你的测试方法有很大的缺陷。一般来说,您必须多次运行操作(可能是数百万或数十亿次)才能获得有意义的结果。否则,您运行基准测试的顺序和调度等可能会给你带来截然不同的结果。

  • @463035818_is_not_an_ai已经指出,您应该使用steady_clock而不是high_resolution_clock进行基准测试(尽管在这种情况下这不太可能产生重大影响)
  • @VLL已经指出,简单地改变construct_test()copy_test()的顺序会得到one function run faster than the other

您可以使用google/benchmark(由QuickBench使用)来获得更有意义的结果。
除了您使用的两种方法之外,至少还有两种方法可以创建/覆盖字符串:

// BenchmarkInit
std::string target_data = std::string(raw_data.begin(), raw_data.end());

// BenchmarkAssignmentOp
std::string target_data;
target_data = std::string(raw_data.begin(), raw_data.end());

// BenchmarkAssign
std::string target_data;
target_data.assign(raw_data.begin(), raw_data.end());

// BenchmarkCopy
std::string target_data;
target_data.resize(raw_data.size());
std::copy(raw_data.begin(), raw_data.end(), target_data.begin());

字符串
对于clang 15,libstdc++,-O3,我们得到以下benchmark results:x1c 0d1x的数据

  • 使用std::string构造函数是最好的,无论是否首先进行了不必要的默认初始化。前两种方法在内部使用std::memcpy,这应该是复制内存最快的方法。
  • std::copy较慢,可能是因为.resize()需要先将内存清零,并且没有很好地优化到memcpy,而是优化到矢量化内存操作。
  • .assign的速度要慢得多,可能是因为与std::copy相比,部分循环展开较少,所以除了复制内存之外,还有很多开销。

即使使用适当的基准测试,您也可以看到意想不到的和戏剧性的差异,并且只有在查看组装时才能理解事情。

相关问题