我在过去的很多场合都注意到C和C ++代码对这些结构使用了以下格式:
class Vector3
{
float components[3];
//etc.
}
class Matrix4x4
{
float components[16];
//etc.
}
class Quaternion
{
float components[4];
//etc.
}
我的问题是,这会导致任何比这更好的缓存性能:
class Quaternion
{
float x;
float y;
float z;
//etc.
}
...因为我假设类成员和函数在连续的内存空间中,无论如何?我目前使用后一种形式,因为我发现它更方便(但我也可以在数组形式中看到实际意义,因为它允许根据正在执行的操作将轴视为任意)。
从受访者那里得到一些建议,我测试了差异,实际上阵列速度较慢 - 我的帧率有3%左右的差异。我实现了operator []来包装Vector3中的数组访问。不确定这是否与它有任何关系,但我怀疑它,因为无论如何应该内联。我能看到的唯一因素是我无法再在Vector3(x, y, z)
上使用构造函数初始化列表。但是,当我使用原始版本并将其更改为不再使用构造函数初始化列表时,它的运行速度比以前慢了很多(小于0.05%)。毫无头绪,但至少现在我知道原来的方法更快。
答案 0 :(得分:3)
这些声明与内存布局不同。
class Quaternion
{
float components[4];
//etc.
}
上面保证元素在内存中是连续的,而如果它们是像上一个例子中那样的单独成员,则允许编译器在它们之间插入填充(例如,使成员与某些地址模式对齐)。
这是否会导致更好或更差的性能取决于您的编译器,因此您必须对其进行分析。
答案 1 :(得分:1)
我认为像这样的优化的性能差异很小。我会说这样的事情属于大多数代码的过早优化。但是,如果您计划对结构进行矢量处理,比如使用CUDA,则结构组合会产生重要的差异。如果感兴趣,请查看第23页http://www.eecis.udel.edu/~mpellegr/eleg662-09s/li.pdf
答案 2 :(得分:1)
我不确定编译器是否设法在此上下文中使用数组时更好地优化代码(例如在联盟中考虑),但是当使用像OpenGL这样的API时,它可以在调用像
这样的函数时进行优化void glVertex3fv(const GLfloat* v);
而不是打电话
void glVertex3f(GLfloat x, GLfloat y, GLfloat z);
因为在后一种情况下,每个参数都是通过值传递的,而在第一个示例中,只传递指向整个数组的指针,函数可以决定复制什么以及何时复制,这样可以减少不必要的复制操作。