游戏的STL,是还是不是?[关闭]


145

每种编程语言都有其标准的容器,算法和其他有用的库。对于C#,Java和Python之类的语言,使用没有标准库的语言实际上是不可想象的。

但是,在我从事过的许多C ++游戏中,我们要么根本不使用STL,要么只使用其中的一小部分,要么使用我们自己的实现。很难说这对我们的游戏是一个明智的决定,还是仅仅由于对STL的无知而做出的决定。

那么... STL是否合适?



1
是的,这就是我所说的“使用我们自己的实现”。:)
慷慨的

3
如果您有机会找到并购买“最佳游戏编程宝石”,那就去做吧。ArenaNet的James Boer发表了一篇题为“在游戏编程中使用STL”的文章,他在其中很好地举例说明了使用STL的情况。
chiguire

实际上,使用没有标准库的Java是可以想象的,它称为J2ME:p
Bart van Heukelom 2010年

1
好问题!
艾伦(Alan)2010年

Answers:


191

早在我从事专业游戏开发工作时,STL太不成熟,而且肿。但这是在10年前。

现在,我从事军事模拟工作,这对性能有更严格的要求(例如帧速率永远不能低于某些FPS)。在军事模拟中,STL被广泛使用。

有些告诉您不要使用STL的人使用这样的论点,即它并不总是解决问题的完美甚至最佳的解决方案。但这不是问题的答案。问题应该是:在游戏中使用STL有天生的错误吗?我会说不,STL在大多数情况下是比用户自己想出的更好的实现。

只要确保您知道如何使用STL,然后在游戏中使用它即可。阅读一些书籍,并查看正在使用的STL中的实现代码。


49
这是非常可靠的建议。“ STL很慢”模因至少已经五年没有出现,甚至可能更长。它会继续存在下去,就像“ Java缓慢”和“ .NET缓慢”废话一样,直到每个人都知道不再如此。STL帮助您编写更好的程序;我要说的是,在大多数情况下(除了某处的0.1%)不使用它是不负责任的。(它不适合一个给定的问题域的要求往往比较的问题解决方式的起诉书,而不是STL自身修复您的代码,乡亲们。)
埃德Ropple

5
@Ed Ropple:我认为问题不在于STL不适合特定问题,而是在于它适合太多问题,这会使其中的代码过于复杂。人们过度使用STL令人恐惧,我认为这就是为什么许多人(包括我自己)根本不使用它的原因之一。就像不久前我看到的一个例子一样,问题是如何从3个数字中获取最大的数字,答案之一是将它们推入std :: vector,然后将std:sort排序。这肯定会迫使不必要的解决方案解决一个非常简单的问题。
西蒙2010年

22
@Simon:在所有应得的尊重下,最后一个例子是极端笨拙的征兆,与STL无关……那个人会用其他语言对可排序的列表进行同样的处理。是他的想法被打破了。
ggambett 2010年

@EdRopple尝试为PPM图像文件实现STL解析器(如果仅针对P6或P3,则总共少于100行代码)。结果代码的一半仅用于跳过注释行,因为STL不提供类似的内容if(stream.nextCharacter() == '#') stream.skipLine();
GameDeveloper 2015年

@DarioOO我不知道该文件格式,但这就是流适配器和过滤器的作用。我是五年前写的那条评论,介意(偶尔还会再来!),但是这些天,我写的任何东西都不是功能性的,基于转换的风格,它不是超级,超性能的关键,而像您这样的问题正在描述解决问题的方法。我真的不关心那么多关于线数(和国际海事组织也应该知道),我在乎的实施正确性,那么清晰,那么性能和然后这样的事情码长。
Ed Ropple

63

我想说的是,最好还是使用STL,除非您确切知道为什么不使用它。

关于STL的事情是这样的:它是由比您聪明的人开发的。这不是冒犯性的,也不是任何东西,仅仅是STL是由实际正在构建STL的人员开发的。它将在平台允许的范围内达到几乎最快的速度,并且通常比家用解决方案要健壮得多(如果您不担心原始速度,那么这将是一个令人担忧的问题,因为您的游戏需要健壮性比您需要的速度要好得多;没有前者,后者就毫无意义。

关于STL实施“世界观”的抱怨让我感到有些愚蠢。他们是容器。它们的操作集有限,因为容器的操作集有限。您正在做什么,这不符合您的意愿?


4
我认为没有人应该证明为什么不应该使用STL。也不要同意整个“使用它,因为它们比您聪明”的说法。STL是围绕问题域的特定视图设计的,而不仅仅是容器,即算法,分配器,迭代器,特征等。这很公平,但这不是查看该问题域的唯一方法
zebrabox 2010年

2
因此,您宁愿自行编写代码,也不愿进行经过广泛测试的强健代码?问题域在项目之间并没有什么不同(除了嵌入式项目之外-如今,即使控制台也具有不错的STL实现!)。不管使用哪种游戏,您的问题都没有什么不同,并且,如果要制造要交付的产品,则负有编写健壮代码的隐含责任。重新实施车轮是否会带来更好的坚固性和灵活性?我倾向于“不”。这不是“唯一的方法”,并不意味着它通常并不优越。
Ed Ropple

20
我会说gamedev是关于制作游戏的,但是可以。如果您的假设太糟糕了,以致您无法进行这种资源分配,那么,是的,您需要退后一步并重新评估它们。但是,当您真正知道自己在做什么时,您也可以使使用STL的应用程序达到令人眼花fast乱的速度,当然也可以使用任何其他实现。了解您的工作>拒绝STL。没有人说STL永远是最好的答案。我的意思是,如果您无法详细说明为什么它不是最佳课程,则应该使用STL。
Ed Ropple

11
我认为这根本没有挑衅性,它的用语是使它牢记在人的记忆中,但这是一种极其保守和直接的立场。简而言之:开发STL的人比发现必须问这个问题的人更了解知识,并且装备更好。如果您不得不问其他人STL是否合适,那么您几乎可以肯定缺少特定领域的知识来充分准备本地解决方案。
罗德普

4
“这将在平台允许的范围内尽快实现。” 这是绝对的事实,因为许多编译器供应商都不必费心重写STL,以至于它确实会从特定体系结构中挤出最大的性能。STL不能保证性能上的任何特征,除了大O之外。O可能像编译器供应商所希望的那样高效或低效。
Kaj 2010年

35

我发现很少有理由不将STL用于游戏。

对于内存分配问题,很多人都不知道,但是您可以为STL容器类编写自定义分配器。分配器基本上是您传递到模板中的策略类,以确定如何执行分配。使用这些功能,通常可以解决所选平台上出现问题的任何内存问题。

当然,如果您正在使用STL并做一些愚蠢的事情,例如将字符串映射映射为大的非指针类型,那么您手头上会遇到更大的问题。


实际上,在映射中使用大型非指针类型是一个好用例,因为stdlib映射要求不使迭代器无效,这会迫使实现使用指针和单独分配的映射元素。游戏的最佳解决方案是使用google::sparse_map或编写自己的游戏。
v.oddou

为什么不密集地图?
GameDeveloper 2015年

23

默认的STL有很多问题,使游戏难以使用,尤其是在内存对齐方面。

定制的变体(例如EA STL)是专门为游戏设计的,可以为您提供更好的内存性能和控制台可用性。根据BSD-3条款,它于2016年成为开源,并在GitHub上有一个存储库


19
STL的内存使用和游戏问题通常可以通过自定义分配器类解决。确实,在我之前的工作中,我们的“自定义”矢量类只是一个薄包装std::vector,覆盖了默认分配器。
布莱尔·霍洛威

1
@Blair Holloway:“自定义分配器是基于类的,而不是基于实例的。分配器需要构造和销毁对象以及对其进行分配。这迫使两个单独的概念混合在一起:分配和构造。这些只是其中的一部分不幸的是,与stl-allocator有关的问题。” EA STL给出了STD分配器损坏的更多有效原因。这不仅仅是“是否可以覆盖它们”。
西蒙2010年

@Simon-我不会说STL的分配器系统很完美,因为事实并非如此。寻找解决方案确实花了我们很长时间。我想说的是,在某些情况下,有可能得到一个可行的,游戏友好的解决方案使用STL和自定义的分配一点工作。
布莱尔·霍洛威

@Simon-详细说明:尽管STL可能很麻烦,但它是经过很好测试且没有错误的代码;如果可以使用它,则可以节省调试自定义解决方案所需的工时。我现在的工作是避免使用STL来使用自制的分配器,并且我不得不花时间调试和重构某些代码,因为它的成熟度与STL不同。
布莱尔·霍洛威

1
@Simon:我在这里参加聚会有点晚了,但是我很好奇您能否给出具体含义的例子。以STL太笼统而无法有效解决的方式解决特定问题的一个好例子是什么?
布拉夫

21

这是迈克·阿克顿(Mike Acton)(在《龙,棘轮与叮当》和《抵抗》声望很高的斯波罗(Spyro)失眠游戏的引擎总监)在这里被问到的话。请注意,通常询问他有关STL和Boost的信息,这些信息与游戏开发人员的用法有关。

STL / Boost,它属于gamedev吗?如果只是一部分,那是哪一部分?

您在这里问两件事,对吗?STL和Boost分别。但实际上,我的答案是相同的:两者本身都没有,但我不鼓励使用它们。任使用鼓励人们适合解决一个问题,而不是寻找一个解决问题的办法。该解决方案应始终适合于手头的数据以及硬件的限制等。STL和Boost都对“世界”有极其狭窄的了解,并且它们的适当使用受到限制。的确,我不鼓励他们,因为它们会立即导致程序员走错方向,我经常说,如果您觉得自己需要一个,那您可能根本就不了解自己的问题。

我还注意到,大多数职业游戏开发人员在C语言上的努力要超过C ++。


18
我不同意在C语言方面的努力。绝大多数游戏开发人员和SDK编写人员都使用C ++。实际上,最后一个主要的C用户是id,甚至Carmack现在都已使用C ++ ...
Goz 2010年

82
阿克顿先生的评论似乎是粗略的。一般来说,STL是一个不错的选择对于那些问题。如果您尝试以某种方式使用STL方法似乎是“错误的”,那么重新评估您的方法并查看您是否实际上在以一种聪明的方式来做可能是一个非常好的主意。根据我的经验,您可能并非经常如此。(IMO,通过在工具的上下文中强烈地理解问题来解决问题,而不是仅仅为了从头进行重做而丢弃工具,这是非常聪明的。)
Ed Ropple 2010年

50
我在STL方面的经验几乎相反。它高效而省时。如果您需要滚动自己的模板库或容器库,那很好。但是不要假装STL(或者说升压)是不好的。我已经在商业iPhone,Nintendo DS,Wii,PC,Mac和Xbox游戏上广泛使用STL。每次我被迫使用别人的“更好”的库时,我都会发现它缺乏缺陷。
布拉夫

5
它在DS上的效果与在我使用过的其他平台上一样出色。我在整个UI和AI代码中都使用了STL。游戏是ds.ign.com/articles/832/832147p1.html。我在一个小工作室,这是惊奇的一部分,这是基金会9的一部分工作
BRaffle

7
迈克全是关于数据的。查看数据表明转换数据的最佳方法。大规模应用它就可以编程了。在这种情况下,他的批评很有道理。STL(和设计模式)建议,我们不检查数据以提供解决方案,而是检查我们的技巧包中的解决方案,以找到适用于数据的解决方案。我并不是要代表Mike发言,但我相信他会建议这种解决问题的方法是倒退的,并且可能导致效率低下或膨胀的解决方案。
丹·奥尔森

19

如果发现由于某种原因重写了STL中已经存在的内容,请停止。使用STL。

经过多年的分析和时间,对STL进行了优化,可以肯定的是,您可能不会编写更有效的内容。这并不是说您应该在可能有更简单解决方案的地方使用STL(例如,在已知数量的东西而不是stl :: list的情况下使用数组),但是如果您正在编写自己的地图实现(基本数据结构,而不是游戏世界地图),您做错了。


7
map <>几乎从来都不是您想要在游戏环境中用于任何高效内存或CPU的东西。尽管hash_map的性能与供应商之间存在很大差异,但是hash_map <>几乎总是一个更好的选择。如果您要构建用于控制台或具有可扩展网络玩法功能的游戏,那么STL绝对太慢或过分膨胀以至您的目的。
Ben Zeigler

3
unordered_map <>现在可以广泛使用,并且在当前的TR1草案中具有极其严格的性能要求。(我认为

5
STL提供算法以及容器。从来没有理由不使用算法的stl版本。例如,std::sort通常在下面使用introsort,其速度非常快而且非常复杂,以至于您不想自己做。
deft_code

事实是unordered_mapC ++ 11或boost都太慢了,您想要的是开放地址哈希映射,例如google :: sparse_map或您自己的。
v.oddou

16

STL是否适合游戏?绝对是 游戏是复杂的软件,STL提供了有助于管理复杂性的功能,因此很好。

是否适合您的平台?不必要。如果要编写控制台,则必须非常注意内存和缓存的使用情况。STL并不十分简单。

我认为我们经常将“游戏”误解为“在嵌入式或定制硬件上运行的高性能实时游戏”,但区别对待很重要。如果您要编写的Windows游戏不想以全屏60fps的速度全屏运行,那么就没有理由避免使用标准库提供的工具。


10

我知道这对聚会来说很晚,但是时间变化和答案仍然存在。C ++ 11进行了相当大的更改,其中许多更改都是​​为了提高C ++和标准库的性能。似乎那些不使用STL或Boost的人也往往不会跟上新标准,使得家用旋转解决方案缺乏重要的改进,当然,并非总是如此。

从90年代中期到今天,我在每个项目中都使用了STL,但在EA的时间很短。我认为反STL方面有一些不使用它的理性原因。这些基本上消失了。自定义分配器是一种解决方案,使用保留是另一种解决方案,不按值传递是第三种解决方案,但是这些非常简单,任何程序员都应该知道这些。不过,更重要的是算法的使用。编译器作者确切知道for_each()的功能,并且可以优化代码。本地循环不会发生这种情况。const对象上的for_each()甚至更好。Microsoft通过多种方法对for_each进行了优化,包括序列化。它们还具有带有parallel_for_each()的AMP库。如果有机会,请与编译器工程师联系。控制台编译器将优化使用的内容,因此 有点鸡鸡蛋问题。微软对C ++ 11的投入非常大,下一个XBox也不例外。我不知道PS4,我们还没有得到。

自定义分配器是处理内存问题的一种方法,但另一种(通常被忽略)的方法是使用基于类的new和delete。这样可以极大地提高性能。

Boost和STL对解决问题的看法很狭窄,这是纯粹的精神错乱。我对通过特性和策略可以自定义STL和Boost中的多少感到惊讶。以不区分大小写的字符串比较为例。

关于较长的链接时间和代码膨胀,新的extern模板应对此有所帮助。通常,我发现较长的编译时间来自过多的耦合和对pch的滥用。

在本地使用STL的最有说服力的理由是,有数百万人可以帮助您使用STL。与往常一样,不要过早优化和测试,测试,测试。


有趣的想法;“ 使用基于类的new和delete ” 是什么意思?您的意思是,通过使用堆上已有的对象来加速进程?
johnbakers

9

这是游戏开发中的热门话题。除了上面提到的EASTL,我个人不建议这样做。我在游戏中遇到了STL的两个主要问题(从技术上讲是“ C ++标准库”,因为STL不再是名称)。1)使用STL时,动态内存分配通常会浪费大量游戏时间。2)STL的使用鼓励了游戏架构的结构数组方法,而数组结构方法则更易于缓存。


如在其他地方提到的,您可以为容器类提供自定义分配器-如果需要,它们可以使用自由列表(预分配的数组)。结构数组与数组结构非常取决于您要执行的操作-没有硬性规定可以确定哪一个更好。
Skizz 2010年

我感谢您的观点,重要的是要充分理解您要解决的问题。但是,尽管如此,我仍然认为我不同意你的结论。每个问题都有使用模式,这些使用模式无法表达给自定义STL分配器,但可以在自定义容器中轻松利用,例如使用平面数组实现的固定块分配器。与对多态类型的向量进行迭代并调用虚拟方法相比,对同类类型的数组进行固定转换将很可能导致更好的缓存一致性。
Terrance Cohen

5

这取决于。项目有多大,平台多少个,时间表如何?

如果您在一个大型项目上,在资源有限的平台上,有大量的时间和预算,那么您可以避免不可避免的地狱,这将使您陷入半百万行代码库的麻烦之中,从而为您节省很多麻烦STL杂乱无章,无法将帧速率保持在30以上,吃掉了足够的RAM来容纳更多资产,并且需要2个小时来构建。

但是,在其他情况下,如果正确应用STL甚至Boost也会非常有用。我从事过使用STL / Boost的选择的工作,并且绝对是编写代码的梦想:更少的错误/泄漏和易于维护的代码意味着更多的时间编写有趣的新功能!特别是对于业余项目,这是动力部门的一项巨大胜利。

知道何时换性能以方便使用!


1
“知道什么时候换性能以方便使用”。是。仅此句话就是任何答案的好答案。确定您的游戏需要达到的目标,咨询同行并确定STL是否会帮助您实现目标或阻碍您。我想说的是,如果您不想为游戏的下一代图形和性能设置标准,STL可能会为您提供帮助。
gkimsey 2012年

4

恕我直言,我说这很合适,因为STL已经很好地工作了,并且针对其完成的任务进行了优化。此外,您正在开发游戏,因此,请使用手边的工具,这些工具可以使您的生活更轻松,并且代码不易出现错误。

当您可以从事游戏的AI,用户体验或其他更好的工作时,为什么还要重新设计轮子呢?测试和调试?


2
实际上,在项目接近尾声时,性能往往是一个关键问题。如果使用STL,则几乎没有进行优化的机会,因为它需要特定的应用程序并以一般方式解决它们。以特定方式解决特定情况(并且无需动态内存分配)几乎总是具有更高的性能。
Terrance Cohen 2010年

2
但是,如果您不希望动态分配内存,那么您不应该使用STL。这就是重点。您自己的代码不会更好,并且肯定会变得更糟。滥用STL 的设计决策是这里的问题,而不是STL,其功能或性能特征。您正在攻击问题的错误部分。
Ed Ropple

4

只要您了解STL,就可以在游戏中使用它。我们的引擎对其进行了广泛的使用,这从来都不是问题。我没有控制台开发方面的经验,这可能是一个完全不同的故事,但是在所有PC平台(Windows / Mac / Linux)上都很好地支持了它。

最重要的是要了解每种容器类型的优点和缺点,并为您要执行的工作选择正确的容器。


4

我的前雇主从使用一组可靠的自定义容器类转变为STL。构建时间增加了,调试的便利性降低了,这两者都非常明显。如果我们从头开始,那么STL(也许使用得更好)可能是有意义的,但是对我来说,从来没有清楚我们在切换到STL时获得了什么东西,可以证明它可以抛出工作,快速,可调试的代码。

对于我的个人项目,STL是否合适取决于项目。如果我想做一些Mike Acton风格的数据驱动,内存和缓存访问优化的工作,那么我至少会考虑使用自己的自定义数据结构。如果我要设计一些算法或游戏原型,而不在乎性能,可伸缩性,目标平台等,那么我将自动获取STL。


4

我为此付出的2美分是STL可以正常工作的。我一直在为PC开发3D游戏引擎(不是AAA质量,但足够先进-脚本实体类型,延迟渲染器,集成的Bullet物理),但我还没有看到容器成为主要瓶颈。每次我尝试并尝试提高性能时,不正确的3D API使用率和糟糕的算法一直是最好的目标(由性能分析确定!)。


3

我已经使用STL制作了游戏,而且我喜欢它,而且效果似乎不错。


3

好问题!一个更具体的问题是,使用STL和Boost无法满足游戏的一些常见要求。

以我的经验,控制台硬件的严格内存限制使任何类型的动态大小的容器都不是一个好主意,无论您的自定义分配器多么聪明。没有故意界限的容器鼓励程序员编写不限制其数据集界限的代码。根据难以跟踪的无数变量,您可能会超出内存限制。我直觉这是现代游戏不稳定的主要原因之一。

此外,模板的过度使用会导致大量代码库中的编译时间很长,并且会膨胀可执行文件的大小,从而使其不再适合ps3上辅助内核的缓存。

但是,对于仅PC的开发,我认为STL和Boost非常好。尽管一般情况下的解决方案并不总是理想的,但它们通常足够好。您对问题的第一个解决方案几乎从来都不是理想的,并且您需要改进或替换不足之处,直到足够好为止。


2

如果STL非常适合您的游戏,则STL非常适合您的游戏。

与在开发过程中做出的所有技术选择一样,您需要权衡利弊–滚动我自己的库会比仅仅使用STL给我更多有益的内存使用,性能和生产率吗?可能 vector与使用现有内存相比,创建使用更多内存,速度较慢并且需要大量维护才能保持功能的实现同样容易。

人们不应该避免在游戏中使用STL,因为其他人可以避免在游戏中使用STL。如果他们权衡了所有选项,他们应该避免使用它,并且他们真正相信另一种实现方式将提高其产品的质量。


2
我100%同意您的意见的最后一部分,但我还要走得更远:如果您可以确切地说明为什么STL不是一个好的选择,请不要使用STL。否则,请执行。货物崇拜(从“哦,游戏开发人员使用C ++!”到“哦,游戏开发人员不使用STL!”的所有内容)都是不健康的。但是,我要对您的第二段提出一个问题:那些天真地以为重新实现STL是一个好主意的人不可能vector比STL的人做得更好。到您可以做到时,您不再认为需要这样做!:-)
Ed Ropple 2010年

2

与大多数问题一样,答案永远不会是“是”或“否”,无论是黑色还是白色。STL非常适合某些问题,将其用于这些问题应该很好。假定它无用是一个错误,但假定它适合在每种情况下使用也是一个错误。

在游戏开发中使用STL时要注意的最大问题是内存分配。STL的默认分配器似乎不太适合游戏开发的首选分配策略。当然可以使用自定义分配器,但是如果您正在考虑是否将STL添加到非STL代码库中,那么这会使整个想法不那么吸引人。

此外,如果您的代码库不是STL,则可能没有足够熟悉STL或模板概念的人来正确实现自定义分配器。


2

我认为讨论可以总结如下:

平庸的应用专用代码<良好的通用代码<良好的应用专用代码

自行开发的解决方案将属于第3类的任何人都肯定知道他们特定问题的原始问题的答案。STL属于类别2。因此,对于需要提出“ 应该使用STL”这个问题的人,答案可能是肯定的。


2

STL可以在PC上使用,因为它的高级虚拟内存系统使谨慎分配内存的需求变得不那么紧要了(尽管仍然必须非常小心)。在虚拟内存设备有限或没有虚拟设备且缓存未命中成本高昂的控制台上,您可能最好编写具有可预测和/或有限内存分配模式的自定义数据结构。(而且在PC游戏项目上做同样的事情当然也不会错。)


1

我认为这个问题确实是一个更大的未决问题-我应该在Y中使用X吗?真正答案的唯一方法是亲自尝试一下。对于发现X很棒的每个人,您都会发现有人说X太可怕了。他们两个都是正确的-对于他们的项目。

与大多数其他学科不同,软件的伟大之处在于,如果发现软件没有按照您希望的方式工作,您以后可以随时进行更改。稍后您会发现STL在该项目中不适合您吗?撕掉它,放在其他地方。不喜欢您如何在对象之间划分职责?重构。不喜欢使用物体吗?用直接的C方法替换它们。不喜欢将所有内容存储在结构和方法中以对其进行操作吗?用C ++对象替换它们。


1
当您是对的时候,重构可能会受到巨大的惩罚。因此从长远来看,提前做出明智的决定而不是任意决定会节省您的时间。
艾伦(Alan)2010年

1

我对STL表示反对。我的原因很简单:

  1. 您不需要STL来编写游戏。甚至不大。
  2. STL大大增加了您的编译时间。
  3. 大量的编译时间可以减少开发过程中的迭代次数。

我认为迭代计数是最重要的,所以我只是避免使用STL和其他任何会减慢迭代速度的开发技术(例如,出于这种原因而进行架构设计,或需要编译的脚本语言)。

代价高昂的迭代会导致庞大的开发团队尝试在几乎没有实际发生的情况下完成工作。我已经看过并听到了,罪魁祸首之一似乎是模板库的编译时间。


1
我同意编译时间。大量的编译时间会使工作量翻倍。例如,如果编译持续5分钟,则您每次将花费10分钟喝咖啡。;)
Ipsquiggle 2010年

我看到这个论点的两面,我必须说我完全同意你的论点,理查德。+1。
工程师
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.