我在一个循环缓冲区的基准测试中偶然发现.任何人都可以解释一个std :: vector如何在这个实例中胜过一个简单的数组?
#include <iostream> #include <vector> struct uint_pair { unsigned int a,b; uint_pair (unsigned int x = 0,unsigned int y = 0) : a(x),b(y) {} }; struct container { unsigned int pos; #ifdef USE_VECTOR std::vector<uint_pair> data; container() : pos(0) { data.resize(16); } #else uint_pair data[16]; container() : pos(0) {} #endif void add(uint_pair val) { data[++pos % 16] = val; } }; int main() { container c; for (unsigned int i = 0; i < 1000000000; i++) c.add(uint_pair{i,i}); std::cout << c.data[0].a << " " << c.data[0].b << std::endl; }
这些是我使用GCC的结果(与Clang类似):
g++ -o bench -std=c++0x -Os main.cpp -D'USE_VECTOR' real 0m8.757s user 0m8.750s sys 0m0.002s g++ -o bench -std=c++0x -Os main.cpp real 0m9.215s user 0m9.209s sys 0m0.002s
解决方法
以下是如何消除差异.而不是添加,请使用如下功能:
void set(unsigned int x,unsigned int y) { ++pos; data[pos % 16].a = x; data[pos % 16].b = y; }
叫这样:
for (unsigned int i = 0; i < 1000000000; i++) c.set(i,i);
这与你完全一样,但它避免语义上创建一个临时对象.看起来当您使用向量时,编译器能够更好地优化临时性.
$g++-4.8 -o bench -std=c++11 -Os main.cpp -DUSE_VECTOR $time ./bench 999999999 999999999 real 0m0.635s user 0m0.630s sys 0m0.002s $g++-4.8 -o bench -std=c++11 -Os main.cpp $time ./bench 999999999 999999999 real 0m0.644s user 0m0.639s sys 0m0.002s
在我的机器上,set和add方法产生与向量相同的性能.只有阵列显示出不同之处.为了进一步提供优化信息,如果使用-O0编译,那么数组方法稍快一些(但是比-Os都要慢10倍以上).
这并不能解释为什么编译器会对这两者有不同的看法.一个向量毕竟是由数组支持的.另外,std :: array的行为与C风格的数组相同.