是STL容器.push_back()顽皮

时间:2011-01-28 17:04:54

标签: c++ arrays api opengl

这可能看起来很糟糕,我很抱歉,我已经为Playstation 2 for uni写了一些代码。我正在为Graphic Synthesizer编写一种API。我使用的语法类似于openGL,它是一个状态机。

所以输入就像

gsBegin(GS_TRIANGLE);

gsColor(...);
gsVertex3f(...);
gsVertex3f(...);
gsVertex3f(...);

gsEnd();

对于具有确定数量的顶点的线/三角形/四边形到目前为止这是很好的,但是像LINE_STRIPTRIANGLE_FAN之类的东西需要不确定的点数。由于时间敏感的性质(这是合理的),因为在这种情况下使用了push_back()方法,因此我被多次警告使用stl容器。

如果没有理由以更好的方式处理未确定数量的情况。目前我有一个可以一次容纳30个顶点的数组,这是处理这种情况的最佳方法吗?

6 个答案:

答案 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,而是使用glDrawArraysglDrawElements之类的内容。

push_back()上的

std::vector是一个快速操作,除非在操作发生时阵列需要增大。将vector容量设置为您认为需要的容量,您应该看到最小的开销。 'Raw'数组通常会稍微快一些,但是你必须处理使用'raw'数组。

答案 3 :(得分:2)

始终可以使用deque

dequevector非常相似,相互毗邻。基本上,它通常被实现为vector数组。

这意味着分配成本较低,但由于双重取消引用,成员访问可能会稍微慢一点(虽然不变),所以我不确定它是否有利于你的情况。

还有LLVM替代方案:SmallVector<T,N>,它为N元素预先分配(在向量中)空间,并且一旦大小有,就会回到使用传统的类似矢量的实现长得太多了。

答案 4 :(得分:1)

在这种情况下使用std::vector的缺点是确保正确管理内存分配。在像PS2这样的系统上(PS3在这方面看起来好一点),内存分配非常慢,如果你没有在矢量中保留适当数量的空间(并且在添加时必须重新调整大小几次)项目),你将减慢你的游戏爬行爬行。如果你知道你的最大尺寸是什么,并在创建矢量时保留它,你就不会有问题。

也就是说,如果此向量将成为临时/局部变量,则每次调用函数时仍将重新分配内存。因此,如果每帧调用此函数,您仍会遇到性能问题。您可以通过使用自定义分配器和/或使向量全局(或成员变量到游戏循环期间将存在的类)来解决这个问题。

答案 5 :(得分:1)

您始终可以使用适当的分配器装备您想要使用的容器,这会考虑到平台的限制和预期的增长/收缩方案等...