C++ 在阵列上循环的最有效方法是什么?(c+;+;)

C++ 在阵列上循环的最有效方法是什么?(c+;+;),c++,arrays,for-loop,optimization,C++,Arrays,For Loop,Optimization,这是一个愚蠢的问题,但它一直困扰着我,我无法用谷歌搜索它 考虑以下数组: struct SomeDataStruct { uint64_t ValueOne; uint64_t ValueTwo; uint64_t ValueThree; }; SomeDataStruct _veryLargeArray[1024]; 现在,这些方法中哪一种能够更快地循环每个元素并对每个元素进行处理 方法1: for (int i = 0; i < 1024; ++i) {

这是一个愚蠢的问题,但它一直困扰着我,我无法用谷歌搜索它

考虑以下数组:

struct SomeDataStruct
{
    uint64_t ValueOne;
    uint64_t ValueTwo;
    uint64_t ValueThree;
};

SomeDataStruct _veryLargeArray[1024];
现在,这些方法中哪一种能够更快地循环每个元素并对每个元素进行处理

方法1:

for (int i = 0; i < 1024; ++i)
{
    _veryLargeArray[i].ValueOne += 1;
    _veryLargeArray[i].ValueTwo += 1;
    _veryLargeArray[i].ValueThree = _veryLargeArray[i].ValueOne + _veryLargeArray[i].ValueTwo;
}
我知道这个问题表面上看起来很愚蠢,但我想知道的是,编译器对实现for循环的每一种给定方式都做了什么聪明/特别的事情吗?在第一种情况下,如果编译器每次都查找BaseArrayPointer+偏移量,那么它可能会占用大量内存,但是如果编译器足够聪明,if将使用整个数组填充二级缓存,并正确处理{}之间的代码

如果编译器每次都解析指针,那么第二种方法就可以解决问题,但这可能会使编译器很难确定if是否可以将整个数组复制到二级缓存中,并将其遍历到那里


对不起,这么愚蠢的问题,我学习C++很有乐趣,已经开始做你想得太多的事情了。如果有人知道是否有“确定的”答案,我只是好奇。

除非您想查看中间汇编语言输出并分析CPU的缓存行为,否则回答这个问题的唯一方法就是分析代码。运行数百次或数千次,看看需要多长时间

如果您想要最快的代码,请编写最简单、最明显的版本,并将其留给优化编译器。如果您尝试使用这样的循环,您可能会混淆编译器,它将无法优化内容

我见过一个简单的C循环编译比手工编码的程序集快,而手工优化的C版本最终比手工编码的程序集慢


另一方面,了解一点缓存和引擎盖下发生的事情是值得的。但通常情况下,当您发现代码不够快时,就会发生这种情况。否则会带来过早优化的风险,这是最重要的。

您在问什么平台?在主要的桌面平台上,“将数组复制到L2”不是编译器的工作,而是MMU硬件。在某些情况下,编译器甚至可能为两个循环生成相同的代码。您不应该注意到任何性能差异。此外,为了可读性,我建议您在这两个选项中的任何一个上使用一个循环范围。要在体系结构上为编译器获得最终答案,唯一的方法是对代码进行概要分析。(好吧,如果循环恰好编译为相同的机器代码,我想您不必实际运行它就知道它们具有相同的性能。)在这种情况下,使用结构或数组将使代码更容易矢量化。我可能应该加入一些关于泄漏抽象法则的内容:因为它与上面的答案略有矛盾。有时,你应该知道引擎盖下发生了什么,当你可以在O(n)中进行时,避免使用n平方算法,等等。
SomeDataStruct * pEndOfStruct = &(_veryLargeArray[1024]);

for (SomeDataStruct * ptr = _veryLargeArray; ptr != pEndOfStruct; ptr += 1)
{
    ptr->ValueOne += 1;
    ptr->ValueTwo += 1;
    ptr->ValueThree = ptr->ValueOne + ptr->ValueTwo;
}