9

我正准备通过std::tuple在包括单个元素在内的很多情况下使用来使我的代码更加通用。我的意思是例如tuple<double>而不是double. 但我决定检查这种特殊情况的性能。

这是简单的性能基准测试:

#include <tuple>
#include <iostream>

using std::cout;
using std::endl;
using std::get;
using std::tuple;

int main(void)
{

#ifdef TUPLE
    using double_t = std::tuple<double>;
#else
    using double_t = double;
#endif

    constexpr int count = 1e9;
    auto array = new double_t[count];

    long long sum = 0;
    for (int idx = 0; idx < count; ++idx) {
#ifdef TUPLE
        sum += get<0>(array[idx]);
#else
        sum += array[idx];
#endif
    }
    delete[] array;
    cout << sum << endl; // just "external" side effect for variable sum.
}

并运行结果:

$ g++ -DTUPLE -O2 -std=c++11 test.cpp && time ./a.out
0  

real    0m3.347s
user    0m2.839s
sys     0m0.485s

$ g++  -O2 -std=c++11 test.cpp && time ./a.out
0  

real    0m2.963s
user    0m2.424s
sys     0m0.519s

我认为元组是严格的静态编译模板,在这种情况下,所有 get<> 函数都可以正常访问变量。顺便说一句,此测试中的内存分配大小是相同的。为什么会发生这种执行时间差异?

编辑:问题在于初始化 tuple<> 对象。为了使测试更准确,必须更改一行:

     constexpr int count = 1e9;
-    auto array = new double_t[count];
+    auto array = new double_t[count]();

     long long sum = 0;

之后可以观察到类似的结果:

$ g++ -DTUPLE -g -O2 -std=c++11 test.cpp && (for i in $(seq 3); do time ./a.out; done) 2>&1 | grep real
real    0m3.342s
real    0m3.339s
real    0m3.343s

$ g++ -g -O2 -std=c++11 test.cpp && (for i in $(seq 3); do time ./a.out; done) 2>&1 | grep real
real    0m3.349s
real    0m3.339s
real    0m3.334s
4

1 回答 1

14

元组所有默认构造值(所以一切都是 0)双打没有默认初始化。

在生成的程序集中,只有在使用元组时才会出现以下初始化循环。否则它们是等价的。

.L2:
    movq    $0, (%rdx)
    addq    $8, %rdx
    cmpq    %rcx, %rdx
    jne .L2
于 2013-10-02T20:26:23.423 回答