Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么std::vector::operator[]比std::vector::at()快5到10倍?_C++_Performance_Visual C++_Vector - Fatal编程技术网

C++ 为什么std::vector::operator[]比std::vector::at()快5到10倍?

C++ 为什么std::vector::operator[]比std::vector::at()快5到10倍?,c++,performance,visual-c++,vector,C++,Performance,Visual C++,Vector,在程序优化过程中,我试图优化一个循环,该循环通过一个向量进行迭代,我发现以下事实:::std::vector::at()比操作符[]慢得多 无论是在发布版本还是调试版本(VS2008 x86)中,操作符[]的速度都是at()的5到10倍 在网上读了一些东西后,我意识到at()具有边界检查功能。好的,但是,将操作速度降低10倍 有什么原因吗?我的意思是,边界检查是一个简单的数字比较,还是我遗漏了什么? 问题是,这一性能下降的真正原因是什么? 此外,有没有办法让它更快呢 我肯定会在其他代码部分(我已

在程序优化过程中,我试图优化一个循环,该循环通过一个向量进行迭代,我发现以下事实:::std::vector::at()比操作符[]慢得多

无论是在发布版本还是调试版本(VS2008 x86)中,操作符[]的速度都是at()的5到10倍

在网上读了一些东西后,我意识到at()具有边界检查功能。好的,但是,将操作速度降低10倍

有什么原因吗?我的意思是,边界检查是一个简单的数字比较,还是我遗漏了什么?
问题是,这一性能下降的真正原因是什么?
此外,有没有办法让它更快呢

我肯定会在其他代码部分(我已经在其中进行了自定义边界检查!)中用[]替换所有at()调用

概念证明:

#define _WIN32_WINNT 0x0400
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#include <conio.h>

#include <vector>

#define ELEMENTS_IN_VECTOR  1000000

int main()
{
    __int64 freq, start, end, diff_Result;
    if(!::QueryPerformanceFrequency((LARGE_INTEGER*)&freq))
        throw "Not supported!";
    freq /= 1000000; // microseconds!

    ::std::vector<int> vec;
    vec.reserve(ELEMENTS_IN_VECTOR);
    for(int i = 0; i < ELEMENTS_IN_VECTOR; i++)
        vec.push_back(i);

    int xyz = 0;

    printf("Press any key to start!");
    _getch();
    printf(" Running speed test..\n");

    { // at()
        ::QueryPerformanceCounter((LARGE_INTEGER*)&start);
        for(int i = 0; i < ELEMENTS_IN_VECTOR; i++)
            xyz += vec.at(i);
        ::QueryPerformanceCounter((LARGE_INTEGER*)&end);
        diff_Result = (end - start) / freq;
    }
    printf("Result\t\t: %u\n\n", diff_Result);

    printf("Press any key to start!");
    _getch();
    printf(" Running speed test..\n");

    { // operator []
        ::QueryPerformanceCounter((LARGE_INTEGER*)&start);
        for(int i = 0; i < ELEMENTS_IN_VECTOR; i++)
            xyz -= vec[i];
        ::QueryPerformanceCounter((LARGE_INTEGER*)&end);
        diff_Result = (end - start) / freq;
    }

    printf("Result\t\t: %u\n", diff_Result);
    _getch();
    return xyz;
}
#定义_WIN32_WINNT 0x0400
#定义WIN32_精益_和_平均值
#包括
#包括
#包括
#在\u向量1000000中定义元素\u
int main()
{
__int64频率、开始、结束、差异结果;
if(!::QueryPerformanceFrequency((大整数*)&freq))
抛出“不受支持!”;
freq/=1000000;//微秒!
:std::向量向量向量;
向量保留(向量中的元素);
for(int i=0;i<向量中的元素;i++)
向量推回(i);
int xyz=0;
printf(“按任意键开始!”);
_getch();
printf(“运行速度测试…\n”);
{//at()
::QueryPerformanceCounter((大整数*)&start);
for(int i=0;i<向量中的元素;i++)
xyz+=向量(i);
::QueryPerformanceCounter((大整数*)&end);
差异结果=(结束-开始)/频率;
}
printf(“结果\t\t:%u\n\n”,差异结果);
printf(“按任意键开始!”);
_getch();
printf(“运行速度测试…\n”);
{//运算符[]
::QueryPerformanceCounter((大整数*)&start);
for(int i=0;i<向量中的元素;i++)
xyz-=vec[i];
::QueryPerformanceCounter((大整数*)&end);
差异结果=(结束-开始)/频率;
}
printf(“结果\t\t:%u\n”,差异结果);
_getch();
返回xyz;
}
编辑:

现在,该值被分配到“xyz”,因此编译器不会“擦除”它。

原因是,可能可以使用单处理器指令执行未经检查的访问。选中访问还必须从内存加载大小,将其与索引进行比较,并(假设它在范围内)跳过条件分支到错误处理程序。在处理抛出异常的可能性时,可能会有更多的麻烦。这将慢很多倍,这正是为什么你有两种选择


如果无需运行时检查即可证明索引在范围内,请使用
运算符[]
。否则,请使用
at()
,或在访问之前添加您自己的检查<代码>运算符[]应该尽可能快一些,但如果索引无效,它会乱成一团。

您对返回值不做任何处理,因此如果编译器内联这些函数,它可以完全优化它们。或者它可以完全优化下标(
[]
)版本。从性能度量的角度来看,没有优化就运行是没有用的,您需要的是一些简单但有用的程序来运行这些函数,这样它们就不会被优化了。例如,您可以洗牌向量(随机交换50000对元素)。

我在我的机器上运行了您的测试代码:

在未优化的调试构建中,两个循环之间的差异是微不足道的

在优化的发布版本中,第二个for循环被完全优化(对
操作符[]
的调用可能是内联的,优化器可以看到该循环什么也不做,并且可以删除整个循环)

如果我改变循环体来做一些实际的工作,例如,
vec.at(I)+
vec[i]+,两个循环之间的差异不显著


我看不出有你所看到的五到十倍的性能差异。

也许你真的应该对元素做些什么,而不是仅仅请求它们,或者编译器可以对其进行优化。我不明白你的意思。解释?尝试在for循环中执行类似于
test\u int+=vec[i]
的操作。由于您没有对vector元素执行任何操作,编译器可以完全优化它。请注意,即使您进行了更改,优化器仍然会赢:它可以看到您从未使用计算的
xyz
值,因此操作仍然是优化的。您可以通过返回
xyz
(它无法优化
main()
)来防止它这样做。@Poni:即使使用了更新的代码,我下面要说的几点仍然有效:当我运行这个程序时,我看不到两个循环之间有显著的性能差异。也许您可以给出一些您看到的测试结果。他在运行调试版本时启用了迭代器调试。@Hans:我的测试是使用默认设置的,因此在调试版本中启用了迭代器调试(但是,我认为这是预期的结果,它们的执行大致相同,因为它启用了
op的绑定检查[]
)。如果我禁用迭代器调试,它会使
op[]
的性能比
at()
提高大约两倍(当我最初发布答案时,我并没有真正关注调试构建的性能,但你是对的:迭代器调试可以在调试构建中产生很大的不同)。如果你幸运的话,它会爆炸的。:)