使用指针或引用来访问一个向量然后迭代它缓存不友好?

The*_*ark 1 c++ performance pointers vector cpu-cache

我有一个指向存储在其他对象中的向量的指针.

vector<Thing>* m_pThings;
Run Code Online (Sandbox Code Playgroud)

然后当我想迭代这个向量时,我使用以下for循环:

for (auto& aThing : *m_pThings){
    aThing.DoSomething();
}
Run Code Online (Sandbox Code Playgroud)

假设Thing::DoSomething()存在.

我的问题是:这个代码在取消引用时是否会导致太多缓存未命中m_pThings?我想知道这一点,因为我故意制作了一个向量,以便所有Things在内存中保持连续并避免缓存未命中,并且想知道是否取消引用这样的指针会导致缓存未命中,从而破坏我的努力.

Kas*_*lai 5

我只是想说,将值传递给for-each语句和传递解除引用的指针之间的区别只是在最坏情况下几个时钟周期的一次性惩罚.for-each语句通过调用begin()传入的对象的函数来工作,该函数返回一个迭代器.然后它只使用迭代器完成其余的工作,在两种情况下都是相同的.不必重复引用指针的重复开销.

在现代处理器上,几乎所有你可以做的操作都不会太缓存不友好,除非你用一些奇异的n次多项式模式寻址内存.即使你的程序在几个不同的地址之间快速跳转,缓存通常也很容易处理这种行为,特别是如果某些地址是静态的,例如你的m_pThings向量.

最后,除非你设计的模式将在整个庞大的程序中使用,否则这些选择并不需要事先进行深入的检查.过早优化是邪恶的,应该不惜一切代价避免!如果它被证明是一个问题,你的探查器将提醒你这个特定的设计吞噬周期的事实,应该重新检查.

如果你真的想知道,基准测试是你最好的选择.当涉及到诸如此类的问题时,没有多少代码分析可以击败简单的基准测试,这些问题本质上非常依赖于特定的硬件实现.虽然并非所有缓存的行为方式都相同,但是当一个CPU可以毫不费力地处理算法时,另一个CPU可能会自行消耗.

所以我的回答基本上归结为:做你认为最清楚和/或最方便的事情,因为它可能并不重要.如果它被证明是一个问题,你可能最好重新考虑算法本身,而不是提高缓存性能.缓存应该被视为奖励,而不是必需品.如果你的代码只能运行一些特定的缓存行为,那你就错了*.

*我要做的一个例外是你是为一个特定的目标编程,比如游戏机或其他专有的嵌入式系统.