STL替代方案

时间:2008-09-17 20:09:47

标签: c++ performance stl debug-build

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

我是一名游戏程序员,这对我所参与的许多项目都是一个问题。当你使用STL容器时,很难获得60 fps。

我在大部分工作中使用MSVC。

15 个答案:

答案 0 :(得分:25)

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

正在审核其中一些调整以包含在C ++标准中。

请注意,即使是EASTL也没有针对非优化案例进行优化。我有一个excel文件w /一段时间了一段时间但我想我已经失去了它,但是对于访问它是这样的:

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

我所取得的最大成功就是滚动自己的容器。你可以将它们降到接近数组[x]的性能。

答案 1 :(得分:21)

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

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

您可以创建第三个构建配置,并关闭检查并使用它来调试性能。我建议你保持一个调试配置但是检查,因为它有助于捕获错误的数组索引和类似的东西。

答案 2 :(得分:10)

如果您正在运行的视觉工作室,您可能需要考虑以下事项:

#define _SECURE_SCL 0
#define _HAS_ITERATOR_DEBUGGING 0

这只适用于迭代器,你正在进行什么类型的STL操作?您可能希望了解优化内存操作;即,使用resize()一次插入多个元素,而不是使用pop / push一次插入一个元素。

答案 3 :(得分:7)

对于大型,性能关键型应用程序,根据您的需求构建自己的容器可能值得投入时间。

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

答案 4 :(得分:4)

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

答案 5 :(得分:4)

如果您使用的是Visual C ++,那么您应该看一下:

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

以及该页面的链接,其中包含MS / Dinkware STL执行的所有调试模式检查的各种成本和选项。

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

答案 6 :(得分:3)

查看EASTL

答案 7 :(得分:3)

MSVC在调试版本中使用了非常重量级的已检查迭代器实现,其他人已经讨论过,所以我不会重复它(但是从那里开始)

您可能感兴趣的另一件事是您的“调试版本”和“版本构建”可能涉及更改(至少)4个与松散相关的设置。

  1. 生成.pdb文件(cl / Zi和link / DEBUG),允许进行符号调试。您可能想要添加/ OPT:ref到链接器选项;链接器在不创建.pdb文件时删除未引用的函数,但是使用/ DEBUG模式它会保留它们(因为调试符号引用它们),除非你明确地添加它。
  2. 使用C运行时库的调试版本(可能是MSVCR * D.dll,但这取决于您正在使用的运行时)。这可归结为/ MT或/ MTd(如果不使用dll运行时则为其他内容)
  3. 关闭编译器优化(/ Od)
  4. 设置预处理器#defines DEBUG或NDEBUG
  5. 这些可以独立切换。第一个在运行时性能上没有任何成本,尽管它增加了大小。第二个使得许多功能更加昂贵,但对malloc和free有很大的影响;调试运行时版本小心地“毒害”它们与值接触的内存,以使未初始化的数据错误清晰。我相信在MSVCP * STL实现中它还消除了通常所做的所有分配池,因此泄漏显示了你想到的块,而不是它所分配的大块内存;这意味着它会使更多对malloc的调用更慢。第三;好吧,那个人做了很多事情(this question对这个问题有一些很好的讨论)。不幸的是,如果你想要单步进行顺利工作,那就需要它。第四个以各种方式影响许多库,但最值得注意的是它编译或消除了assert()和朋友。

    因此,您可以考虑使用这些选项中较少的组合进行构建。我大量使用带有符号(/ Zi和link / DEBUG)和断言(/ DDEBUG)的构建,但仍然进行了优化(/ O1或/ O2或您使用的任何标志)但是保留了堆栈帧指针清除回溯(/ Oy-)并使用正常的运行时库(/ MT)。这接近我的发布版本并且是半可调试的(回溯很好,单步执行在源级别有点古怪;当然,程序集级别工作正常)。您可以拥有许多您想要的配置;只需克隆你的第一个版本,然后打开调试的任何部分就好了。

答案 8 :(得分:3)

对不起,我不能发表评论,所以这里有一个答案:EASTL现在可以在github上找到:https://github.com/paulhodge/EASTL

答案 9 :(得分:1)

Ultimate ++有自己的容器集 - 不确定你是否可以独立于库的其余部分使用它们:http://www.ultimatepp.org/

答案 10 :(得分:1)

ACE library怎么样?它是一个面向对象通信软件的开源面向对象框架,但它也有一些容器类。

答案 11 :(得分:1)

使用C ++中的面向对象设计模式检出数据结构和算法 由Bruno Preiss撰写 http://www.brpreiss.com/

答案 12 :(得分:1)

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

编辑:Qt已经在LGPL下发布,这通常可以在商业产品中使用它而不用商业版本(也存在)。

答案 13 :(得分:0)

STL容器不应该在调试或其他任何地方“非常慢”地运行。也许你在滥用它们。你是不是在调试中运行像ElectricFence或Valgrind这样的东西?他们放慢了许多分配的速度。

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

答案 14 :(得分:0)

还有ETL https://www.etlcpp.com/。该库特别针对时间关键型(确定性)应用程序

从网页上:

  

ETL并非旨在完全替代STL,而是补充   它。其设计目标涵盖四个主要领域。

     
      
  • 创建一组容器,这些容器的大小或最大大小在编译时确定。这些容器应在很大程度上   等效于STL中提供的内容,并带有兼容的API。
  •   
  • 与C ++ 03兼容,但要实现尽可能多的C ++ 11添加。
  •   
  • 具有确定性的行为。
  •   
  • 添加标准库中不存在的其他有用组件。
  •   
     

嵌入式模板库旨在降低资源消耗   嵌入式应用程序。它定义了一组容器,算法和   实用程序,其中一些模仿STL的一部分。没有动态   内存分配。该库不使用堆。全部   容器(除了侵入式)具有固定的容量   所有内存分配将在编译时确定。图书馆是   适用于所有支持C ++ 03的编译器。