这可能看起来很糟糕,我很抱歉,我已经为Playstation 2 for uni写了一些代码。我正在为Graphic Synthesizer编写一种API。我使用的语法类似于openGL,它是一个状态机。
所以输入就像
gsBegin(GS_TRIANGLE);
gsColor(...);
gsVertex3f(...);
gsVertex3f(...);
gsVertex3f(...);
gsEnd();
对于具有确定数量的顶点的线/三角形/四边形到目前为止这是很好的,但是像LINE_STRIP
或TRIANGLE_FAN
之类的东西需要不确定的点数。由于时间敏感的性质(这是合理的),因为在这种情况下使用了push_back()方法,因此我被多次警告使用stl容器。
如果没有理由以更好的方式处理未确定数量的情况。目前我有一个可以一次容纳30个顶点的数组,这是处理这种情况的最佳方法吗?
答案 0 :(得分:5)
Vector push_back
已经分摊了常量时间复杂度,因为它以指数方式增加了向量的容量。 (我假设你正在使用向量,因为它适用于这种情况。)但是,实际上,渲染代码对性能非常敏感,因此如果push_back
导致向量重新分配,性能可能会受到影响。
您可以在添加之前预留容量来阻止重新分配。如果你打电话给myvec.reserve(10);
,你可以保证在矢量重新分配之前能够添加10个元素。
然而,这仍然需要提前知道您需要多少元素。此外,如果您创建并销毁许多不同的向量,您仍然需要进行大量的内存分配。相反,只需对所有顶点使用一个向量,然后重复使用它。调用clear()
会将其返回为空,同时保持其分配的容量。这样你实际上不需要保留任何东西 - 你使用它的前几次它会重新分配和增长,但一旦达到它的峰值大小,它就不需要再重新分配了。关于这一点的好处是向量找到它需要的大致大小,一旦它“热身”就没有进一步的分配,所以它是高性能的。
简而言之:
std::vector
push_back
尽可能多地clear()
。在实践中,这将与C数组一样好,但没有大小的硬性限制。
答案 1 :(得分:3)
push_back
已经摊销的时间复杂度,他们会很高兴。
答案 2 :(得分:2)
首先,如果可以,请避免使用glBegin
/ glEnd
,而是使用glDrawArrays
或glDrawElements
之类的内容。
push_back()
上的 std::vector
是一个快速操作,除非在操作发生时阵列需要增大。将vector
容量设置为您认为需要的容量,您应该看到最小的开销。 'Raw'数组通常会稍微快一些,但是你必须处理使用'raw'数组。
答案 3 :(得分:2)
始终可以使用deque
。
deque
与vector
非常相似,相互毗邻。基本上,它通常被实现为vector
数组。
这意味着分配成本较低,但由于双重取消引用,成员访问可能会稍微慢一点(虽然不变),所以我不确定它是否有利于你的情况。
还有LLVM替代方案:SmallVector<T,N>
,它为N
元素预先分配(在向量中)空间,并且一旦大小有,就会回到使用传统的类似矢量的实现长得太多了。
答案 4 :(得分:1)
在这种情况下使用std::vector
的缺点是确保正确管理内存分配。在像PS2这样的系统上(PS3在这方面看起来好一点),内存分配非常慢,如果你没有在矢量中保留适当数量的空间(并且在添加时必须重新调整大小几次)项目),你将减慢你的游戏爬行爬行。如果你知道你的最大尺寸是什么,并在创建矢量时保留它,你就不会有问题。
也就是说,如果此向量将成为临时/局部变量,则每次调用函数时仍将重新分配内存。因此,如果每帧调用此函数,您仍会遇到性能问题。您可以通过使用自定义分配器和/或使向量全局(或成员变量到游戏循环期间将存在的类)来解决这个问题。
答案 5 :(得分:1)
您始终可以使用适当的分配器装备您想要使用的容器,这会考虑到平台的限制和预期的增长/收缩方案等...