我真的很讨厌使用 STL 容器,因为它们使我的代码的调试版本运行得非常缓慢。其他人使用什么来代替具有合理性能的调试构建的 STL?
我是一名游戏程序员,这在我从事的许多项目中一直存在问题。当你对所有东西都使用 STL 容器时,很难达到 60 fps。
我的大部分工作都使用 MSVC。
我真的很讨厌使用 STL 容器,因为它们使我的代码的调试版本运行得非常缓慢。其他人使用什么来代替具有合理性能的调试构建的 STL?
我是一名游戏程序员,这在我从事的许多项目中一直存在问题。当你对所有东西都使用 STL 容器时,很难达到 60 fps。
我的大部分工作都使用 MSVC。
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
我取得的最大成功是滚动自己的容器。您可以将它们降低到接近数组 [x] 的性能。
我的经验是,设计良好的 STL 代码在调试版本中运行缓慢,因为优化器已关闭。STL 容器发出大量对构造函数和 operator= 的调用(如果它们是轻量级的)在发布版本中被内联/删除。
此外,Visual C++ 2005 及更高版本在发布和调试版本中都启用了 STL 检查。对于重 STL 的软件来说,它是一个巨大的性能消耗者。可以通过为所有编译单元定义 _SECURE_SCL=0 来禁用它。请注意,在不同的编译单元中具有不同的 _SECURE_SCL 状态几乎肯定会导致灾难。
您可以在关闭检查的情况下创建第三个构建配置,并使用它来调试性能。我建议您保留调试配置并进行检查,因为捕获错误的数组索引和类似的东西非常有帮助。
如果您正在运行视觉工作室,您可能需要考虑以下事项:
#define _SECURE_SCL 0
#define _HAS_ITERATOR_DEBUGGING 0
这仅适用于迭代器,您正在执行哪种类型的 STL 操作?你可能想看看优化你的内存操作;即,使用 resize() 一次插入多个元素,而不是使用 pop/push 一次插入一个元素。
对于大型、性能关键的应用程序,构建您自己的容器专门为您的需求量身定制可能值得花时间投资。
我在这里谈论的是真正的游戏开发。
I'll bet your STL uses a checked implementation for debug. This is probably a good thing, as it will catch iterator overruns and such. If it's that much of a problem for you, there may be a compiler switch to turn it off. Check your docs.
如果您使用的是 Visual C++,那么您应该看看这个:
http://channel9.msdn.com/shows/Going+Deep/STL-Iterator-Debugging-and-Secure-SCL/
以及该页面的链接,其中涵盖了 MS/Dinkware STL 所做的所有调试模式检查的各种成本和选项。
如果您要问这样一个依赖于平台的问题,最好也提及您的平台......
MSVC 在调试版本中使用了一个非常重量级的检查迭代器实现,其他人已经讨论过,所以我不会重复它(但从那里开始)
您可能感兴趣的另一件事是您的“调试构建”和“发布构建”可能涉及更改(至少)4 个只是松散相关的设置。
这些可以独立切换。第一个在运行时性能上没有任何成本,尽管它增加了大小。第二个让一些函数更昂贵,但对 malloc 和 free 的影响巨大;调试运行时版本小心地用值“毒化”它们接触的内存,以清除未初始化的数据错误。我相信通过 MSVCP* STL 实现,它还消除了通常完成的所有分配池,因此泄漏准确地显示了您认为的块,而不是它一直在分配的更大的内存块;这意味着它会在更慢的情况下对 malloc 进行更多调用。第三; 好吧,那个人做了很多事情(这个问题对这个主题有一些很好的讨论)。不幸的是,如果您希望单步运行顺利,则需要它。第四个以各种方式影响许多库,但最值得注意的是它编译或消除了 assert() 和朋友。
因此,您可能会考虑使用这些选择的较少组合进行构建。我大量使用具有符号(/Zi 和链接 /DEBUG)和断言(/DDEBUG)的构建,但仍然优化(/O1 或 /O2 或您使用的任何标志)但堆栈帧指针保留用于清除回溯 (/Oy-) 并使用正常的运行时库 (/MT)。这执行接近我的发布版本并且是半可调试的(回溯很好,单步执行在源代码级别有点古怪;组装级别当然可以正常工作)。你可以有很多你想要的配置;只需克隆您的发行版并打开调试的任何部分似乎有用。
查看EASTL。
抱歉,我不能发表评论,所以这里有一个答案:EASTL 现在可以在 github 上获得:https ://github.com/paulhodge/EASTL
ACE 库呢?它是一个开源的面向对象的并发通信软件框架,但它也有一些容器类。
使用 C++ 中的面向对象设计模式检查数据结构和算法 作者:Bruno Preiss http://www.brpreiss.com/
Ultimate++ 有自己的一组容器 - 不确定您是否可以将它们与库的其余部分分开使用:http ://www.ultimatepp.org/
STL containers should not run "really slowly" in debug or anywhere else. Perhaps you're misusing them. You're not running against something like ElectricFence or Valgrind in debug are you? They slow anything down that does lots of allocations.
All the containers can use custom allocators, which some people use to improve performance - but I've never needed to use them myself.
还有 ETL https://www.etlcpp.com/。该库特别针对时间关键(确定性)应用程序
从网页:
ETL 并非旨在完全取代 STL,而是对其进行补充。其设计目标涵盖四个主要领域。
- 创建一组容器,其中大小或最大大小在编译时确定。这些容器应该在很大程度上等同于 STL 中提供的容器,并具有兼容的 API。
- 与 C++ 03 兼容,但尽可能多地实现 C++ 11 的添加。
- 有确定性的行为。
- 添加标准库中不存在的其他有用组件。
嵌入式模板库专为资源较少的嵌入式应用程序而设计。它定义了一组容器、算法和实用程序,其中一些模拟了 STL 的一部分。没有动态内存分配。该库不使用堆。所有容器(除了侵入式类型)都具有固定容量,允许在编译时确定所有内存分配。该库适用于任何支持 C++03 的编译器。