【问题标题】:Copy constructor works faster on copying std::vector<int64_t> than std::copy复制构造函数在复制 std::vector<int64_t> 时比 std::copy 更快
【发布时间】:2020-08-06 14:17:15
【问题描述】:
#include <iostream>
#include <vector>
#include <chrono>
#include <string.h>

std::vector<int64_t> vec;
static const int64_t N = 100000000;
static const int64_t M = N - 1;

void func1() {
    std::cout << __FUNCTION__ << std::endl;
    std::vector<int64_t> dst;
    dst.resize(M);
    std::copy(vec.begin(), vec.begin() + M, dst.begin());
}

void func2() {
    std::cout << __FUNCTION__ << std::endl;
    std::vector<int64_t> dst;
    dst.resize(M);
    memcpy(&dst[0], &vec[0], M * sizeof(int64_t));
}
void func3() {
    std::cout << __FUNCTION__ << std::endl;
    std::vector<int64_t> dst(vec);
    dst.resize(M);
}

int main(int argc, char* argv[]) {
    vec.resize(N);
    for (int i = 0; i < N; i++) {
        vec[i] = i;
    }

    auto begin = std::chrono::steady_clock::now();
    if (argc == 1) {
        func1();
    } else if (argc == 2) {
        func2();
    } else {
        func3();
    }
    auto end = std::chrono::steady_clock::now();
    std::cout << "Time difference = "
        << std::chrono::duration_cast<std::chrono::microseconds> \
        (end - begin).count()
        << "[µs]" << std::endl;
    return 0;
}

我认为 std::copy 可能比复制构造函数稍快,如func1() vs func3()

但事实证明func3() 的性能最好。为什么?

函数3 时间差 = 658007[µs]

函数2 时差 = 823092[µs]

函数1 时差 = 838711[µs]

我还测试了 std::vector, func1func3 快。 SomeStruct 包括 std::string

struct A {
    A(int64_t a) : A_(a) {}
    int64_t a_;
};

编译命令:g++ test.cpp -std=c++11 我跑了几次,结果似乎都一样。

【问题讨论】:

  • “我认为 std::copy 可能比复制构造函数稍微快一些” - 为什么?
  • std::copy 是用于复制的通用函数。给定类的复制构造函数,知道该类的内部结构,并且知道在这些内部结构中复制数据的最有效方法,而通用函数无法知道。
  • 什么编译器?什么编译选项?你运行了多少次,结果有多稳定?
  • 是的,所以您通常应该使用-O3 进行基准测试(或任何您的标准发布级别)。运行“几次”和“看起来”相同的事情也是一个担忧——我通常会运行数百次并查看平均值、方差、丢弃异常值等。即使你不使用它,您可以查看gbench 的长度,以获得良好的测量结果。

标签: c++ performance vector


【解决方案1】:

复制构造函数可以将源向量的内容直接复制到新分配的未初始化内存中,特别是如果包含的类型是原始类型或 POD。矢量实现通常为此进行了优化。另一方面,对resize() 的调用必须用默认值(或您为resize() 指定的值)填充新分配的空间,因为向量元素不能未初始化。这显然需要额外的时间。这就是 func1()func(2) 速度较慢的原因。

【讨论】:

  • 使用 as-if 规则,编译器可能会为所有人生成相同的代码(因为 capacity 可能不同,可能不一样,但想法就在这里)。
猜你喜欢
  • 2012-11-03
  • 2013-02-05
  • 2016-08-12
  • 2018-03-12
  • 2020-10-05
  • 1970-01-01
  • 2023-03-31
  • 1970-01-01
  • 2011-04-27
相关资源
最近更新 更多