什么是更快和/或更好?
vector<myType> myVec;
int i;
myType current;
for( i = 0; i < 1000000; i ++ )
{
current = myVec[ i ];
doSomethingWith( current );
doAlotMoreWith( current );
messAroundWith( current );
checkSomeValuesOf( current );
}
或
vector<myType> myVec;
int i;
for( i = 0; i < 1000000; i ++ )
{
doSomethingWith( myVec[ i ] );
doAlotMoreWith( myVec[ i ] );
messAroundWith( myVec[ i ] );
checkSomeValuesOf( myVec[ i ] );
}
我目前正在使用第一个解决方案。每秒真的有数百万次调用,每一位比较/移动都是性能问题。
答案 0 :(得分:11)
第一个版本可能不必要地昂贵,因为它依赖于在向量中创建对象的副本。除非myType
是一个非常小且简单的对象,例如int
,否则存储引用可能是个更好的主意。它也应该在你需要时声明 ,而不是更早,以限制可能的别名问题,否则会导致编译器发出效率较低的代码:
vector<myType> myVec;
for(int i = 0; i < 1000000; i ++ )
{
myType& current = myVec[ i ];
doSomethingWith( current );
doAlotMoreWith( current );
messAroundWith( current );
checkSomeValuesOf( current );
}
创建副本而不是使用引用的一个优点是,它可能导致编译器将对象加载到寄存器中,而不是在每次访问时从内存中读取它。所以这两个版本都值得一试。
当然,复制与参考建议也适用于您的每个功能。他们是通过价值还是参考来论证?根据他们对它的处理方式以及myType
的定义方式,可能会比另一个更快。
第二个版本存在缺陷,因为它(除非编译器能够优化它)需要在每个时间内查找内存中的对象。根据您的STL实现,由于operator[]
上的边界检查,可能还会产生一些开销。
创建一个临时的第一个,然后传递给你的每个函数是正确的方法。问题是该临时值是否应为值类型(myType
)或引用类型(myType&
/ const myType&
)
可能值得探索的另一个选项是将每个函数调用放在它自己的单独循环中。这在某些方面会损害数据局部性,但如果某些函数使用大量本地数据,则可能会表现得更好。它也可能在指令缓存中发挥得更好。
但实际上,表现非常复杂。高速缓存,乱序执行,myType
的确切语义(特别是其复制构造函数和大小)以及编译器执行的优化量都是我们所不知道的。所以我们无法给你一个可靠的答案。
猜猜谁可以:你的编译器。写测试。试试两个。时间结果。选择更快的一个。
答案 1 :(得分:1)
除了避免多次访问同一索引并使用引用以避免复制外,您还可以在函数中使用 fastcall 调用约定。它指示编译器在可能的情况下传递寄存器中的参数,而不是将推送到堆栈。
但是,fastcall不是标准化的,因此它是供应商特定的。
答案 2 :(得分:0)
取决于您的类型的赋值运算符。你希望通过参考这些功能来传递?但对于所有表现问题,如果对您来说很重要,请自行测试您的具体案例。
答案 3 :(得分:0)
在格式方面,我建议如下(在初始化时声明,使用const myType&amp;):
vector myVec; for(int i = 0; i < 1000000; i++){ const myType& current = myVec[i]; doSomethingWith(current); doAlotMoreWith(current); messAroundWith(current); checkSomeValuesOf(current); }
但是,就原始问题而言,使用名为current
的临时变量至少与每次使用myVec[i]
一样快。但是,有可能优化编译器将删除对myVec的冗余查找(即使用您的临时赋值解决方案)...通常,如果您在不使用任何非const的情况下重复声明成员函数声明为“const”成员函数,编译器可以自由创建一个临时的并只执行一次调用,将结果保存到本地临时。