STL替代

时间:2020-03-05 18:59:52  来源:igfitidea点击:

我真的很讨厌使用STL容器,因为它们使我的代码的调试版本运行得非常慢。别人使用什么代替具有合理性能的STL进行调试构建?

我是一名游戏程序员,这在我从事的许多项目中都是一个问题。当我们使用STL容器进行所有操作时,很难获得60 fps。

我的大部分工作都使用MSVC。

解决方案

回答

我敢打赌,STL使用已检查的实现进行调试。这可能是一件好事,因为它将捕获迭代器超载等。如果这对我们来说是个大问题,则可能有编译器开关将其关闭。检查文档。

回答

STL容器在调试或者其他任何地方都不应"真正缓慢地"运行。也许我们是在滥用它们。我们在调试中没有遇到类似于ElectricFence或者Valgrind的问题吗?他们放慢了所有分配工作的速度。

所有的容器都可以使用自定义分配器,有些人可以使用它们来提高性能,但是我从来不需要自己使用它们。

回答

如果我们使用的是Visual C ++,则应查看以下内容:

http://channel9.msdn.com/shows/Going+Deep/STL-Iterator-Debugging-and-Secure-SCL/

以及该页面上的链接,这些链接涵盖了MS / Dinkware STL进行的所有调试模式检查的各种成本和选项。

如果我们要问这样一个与平台相关的问题,那么也提及平台也是一个好主意...

回答

签出EASTL。

回答

Ultimate ++有其自己的容器集,不确定是否可以将它们与库的其余部分分开使用:http://www.ultimatepp.org/

回答

如果我们运营的视觉工作室,则可能需要考虑以下事项:

#define _SECURE_SCL 0
#define _HAS_ITERATOR_DEBUGGING 0

仅用于迭代器,我们要执行哪种类型的STL操作?我们可能需要考虑优化内存操作。即,使用resize()一次插入多个元素,而不是一次使用pop / push一次插入一个元素。

回答

ACE库呢?它是用于并发通信软件的开源面向对象框架,但是它也具有一些容器类。

回答

我的经验是,由于关闭了优化程序,因此设计良好的STL代码在调试版本中运行缓慢。 STL容器会向构造函数和operator =发出大量调用,这些调用会在发布版本中内联/删除(如果它们很轻便)。

另外,Visual C ++ 2005及更高版本在发布和调试版本中都启用了STL检查。对于STL繁重的软件来说,这是一个巨大的性能消耗。可以通过为所有编译单元定义_SECURE_SCL = 0来禁用它。请注意,在不同的编译单元中具有不同的_SECURE_SCL状态几乎肯定会导致灾难。

我们可以通过关闭检查来创建第三个构建配置,并使用它来进行性能调试。我建议我们保留调试配置并进行检查,因为捕获错误的数组索引和类似的东西非常有帮助。

回答

EASTL是有可能的,但仍然不是完美的。 Electronic Arts的Paul Pedriana对游戏应用程序性能方面的各种STL实现进行了调查,其摘要如下:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2271.html

对这些调整中的某些调整正在审查中,以纳入C ++标准。

请注意,即使是EASTL也无法针对未优化的情况进行优化。我有一个带有一段时间的Excel文件,但我想我已经丢失了,但是要访问它就像:

debug   release
STL      100        10
EASTL     10         3
array[i]   3         1

我获得的最大成功是滚动自己的容器。我们可以将这些性能降低到接近array [x]的性能。

回答

对于大型,性能至关重要的应用程序,构建专门针对需求的自己的容器可能值得花费时间。

我在这里谈论真正的游戏开发。

回答

C ++中具有面向对象设计模式的检出数据结构和算法
布鲁诺·普雷斯(Bruno Preiss)
http://www.brpreiss.com/

回答

MSVC在调试版本中使用了非常重要的检查迭代器实现,其他人已经讨论过了,因此我不再重复(但从此处开始)

我们可能会感兴趣的另一件事是,"调试版本"和"发行版本"可能涉及更改(至少)仅松散相关的4个设置。

  • 生成一个.pdb文件(cl / Zi和链接/ DEBUG),该文件允许进行符号调试。我们可能想将/ OPT:ref添加到链接器选项;链接器在未制作.pdb文件时会丢弃未引用的函数,但是在/ DEBUG模式下,除非我们明确添加,否则链接器将保留所有未引用的函数(因为调试符号引用了它们)。
  • 使用C运行时库的调试版本(可能是MSVCR * D.dll,但这取决于我们使用的运行时)。可以归结为/ MT或者/ MTd(如果不使用dll运行时,则可以归为其他)
  • 关闭编译器优化(/ Od)
  • 设置预处理器#define DEBUG或者NDEBUG

这些可以独立切换。第一个虽然增加了大小,但在运行时性能上不付出任何代价。第二种方法使许多功能更昂贵,但对malloc和free具有巨大影响;调试运行时版本会小心地使用值"毒化"它们接触的内存,以清除未初始化的数据错误。我相信通过MSVCP * STL实现,它还消除了通常需要完成的所有分配池,因此泄漏恰好显示了我们认为的块,而不是它正在分配的更大的内存;这意味着在它们之上进行更多对malloc的调用要慢得多。第三;好吧,那可以做很多事情(这个问题对该主题有一些很好的讨论)。不幸的是,如果我们希望单步操作顺利进行,则需要它。第四种以各种方式影响许多库,但是最值得注意的是,它可以在assert()和Friends中编译或者消除。

因此,我们可以考虑使用这些选项的较小组合来进行构建。我大量使用具有符号(/ Zi和链接/ DEBUG)和断言(/ DDEBUG)的构建,但仍进行了优化(/ O1或者/ O2或者我们使用的任何标志),但保留了堆栈帧指针清除回溯(/ Oy-)并使用正常的运行时库(/ MT)。这与我的发行版本很接近,并且是半可调试的(回溯很好,在源代码级别,单步执行有些古怪;汇编级别当然可以工作)。但是,我们可以具有许多所需的配置。只需克隆发行版一并打开调试中似乎有用的任何部分即可。

回答

Qt用不同的接口重新实现了大多数c ++标准库的东西。它看起来不错,但是对于商业许可版本来说可能会很昂贵。

编辑:此后,Qt已在LGPL下发布,通常可以在不使用商业版本(也仍然存在)的情况下将其用于商业产品。