好的,这里的示例代码比较了面向对象编程 (OOP) 解决方案与更新一堆球的面向数据设计 (DOD) 解决方案。
const size_t ArraySize = 1000;
class Ball
{
public:
float x,y,z;
Ball():
x(0),
y(0),
z(0)
{
}
void Update()
{
x += 5;
y += 5;
z += 5;
}
};
std::vector<Ball> g_balls(ArraySize);
class Balls
{
public:
std::vector<float> x;
std::vector<float> y;
std::vector<float> z;
Balls():
x(ArraySize,0),
y(ArraySize,0),
z(ArraySize,0)
{
}
void Update()
{
const size_t num = x.size();
if(num == 0)
{
return;
}
const float* lastX = &x[num - 1];
float* pX = &x[0];
float* pY = &y[0];
float* pZ = &z[0];
for( ; pX <= lastX; ++pX, ++pY, ++pZ)
{
*pX += 5;
*pY += 5;
*pZ += 5;
}
}
};
int main()
{
Balls balls;
Timer time1;
time1.Start();
balls.Update();
time1.Stop();
Timer time2;
time2.Start();
const size_t arrSize = g_balls.size();
if(arrSize > 0)
{
const Ball* lastBall = &g_balls[arrSize - 1];
Ball* pBall = &g_balls[0];
for( ; pBall <= lastBall; ++pBall)
{
pBall->Update();
}
}
time2.Stop();
printf("Data Oriented design time: %f\n",time1.Get_Microseconds());
printf("OOB oriented design time: %f\n",time2.Get_Microseconds());
return 0;
}
现在,这确实在 Visual Studio 中编译和运行,但我想知道是否允许我这样做,应该能够可靠地做到这一点:
const float* lastX = &x[num - 1];//remember, x is a std::vector of floats
float* pX = &x[0];//remember, x is a std::vector of floats
float* pY = &y[0];//remember, y is a std::vector of floats
float* pZ = &z[0];//remember, z is a std::vector of floats
for( ; pX <= lastX; ++pX, ++pY, ++pZ)
{
*pX += 5;
*pY += 5;
*pZ += 5;
}
据我了解,std::vector 中的数据应该是连续的,但我不确定因为如果这将成为另一个平台上的问题,如果它违反标准,它是如何在内部存储的。此外,这是我能够让 DOD 解决方案超越 OOP 解决方案的唯一方法,任何其他迭代方式都没有那么好。我可以使用迭代器,但我很确定它可能只会比启用优化的 OOP 更快,也就是在发布模式下。
那么,这是做 DOD 的好方法吗(最好的方法?),这是合法的 c++ 吗?
[编辑] 好的,对于国防部来说,这是一个糟糕的例子;x,y,z 应封装在 Vector3 中。因此,虽然 DOD 在调试中比 OOP 运行得更快,但在发布时却是另一回事。同样,这是您希望如何有效使用 DOD 的一个不好的示例,尽管如果您需要同时访问大量数据,它确实显示了它的缺点。正确使用 DOD 的关键是“根据访问模式设计数据”。