STL替代
我真的很讨厌使用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下发布,通常可以在不使用商业版本(也仍然存在)的情况下将其用于商业产品。