不使用STL的原因是什么?

15

你的意思是完全不使用STL,即“禁止”STL,还是只是重写一些自己的类,而不是在已经有STL类可以完成你想要的任务的情况下使用STL类。 - CashCow
10个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
6

如果你不能使用 RTTI 和/或异常处理,你可能会发现 STL 的某些部分无法正常工作。例如,原生 Android 应用程序就是这种情况。因此,如果它不能满足你的需求,这就是不使用它的原因!


1
请澄清一下,哪些STL部分在没有异常或RTTI的情况下无法正常工作? - smerlin
所有容器都会抛出异常,这可能会成为一个问题。 - Axel Gneiting
STL集合如果无法分配内存,会抛出bad_alloc异常。 - CashCow
1
@CashCow:默认分配器(而不是容器本身)使用new并可能抛出bad_alloc异常。例如,您可以使用一个在内存不足时核心转储的分配器,从而避免bad_alloc异常。 - Fred Nurk

6
当您选择使用像Qt这样的框架时,您可能考虑使用来自Qt的列表、向量等,而不是STL。在这种情况下不使用STL可以避免在需要在GUI中使用它们时从STL转换为Qt等效物。 这是有争议的,并非每个人都想使用Qt的所有内容。 来自http://doc.qt.nokia.com/latest/containers.html: 这些容器类旨在比STL容器更轻、更安全、更易于使用。如果您不熟悉STL或更喜欢按照“Qt方式”操作,您可以使用这些类代替STL类。

3
我能认同STL容器并不完全安全且易于使用的想法,但它们之所以如此轻巧(无损性能是一个主要目标),正因为如此。因此,声称Qt的容器比STL的更"轻量级"对我来说似乎有些奇怪。(免责声明:我完全不了解Qt.) - sbi

5

不完全正确。除非该库只提供一种功能(这并不是标准库的情况),否则禁止使用整个库是没有道理的。应该根据每个函数的特点来评估提供的功能。例如,你可能会认为需要一个执行比 vector 更具体目的的容器,但这并不是禁止使用 dequeiostreamfor_each 的借口。

更重要的是,通过模板生成的代码不会比手写的等效代码更臃肿。拒绝使用 std::vector 并编写自己的 float 和 double 向量的等效代码并不能减少代码膨胀。尤其是在2011年,可执行文件的大小在绝大多数情况下与媒体等其他东西相比毫无意义。


4
如果你非常关心可执行文件的大小,那么你可能不想在程序中使用STL。例如,uTorrent就没有使用STL,这也是它如此小的原因之一。由于STL非常依赖于模板(毕竟它是标准模板库),所以每次在处理STL时使用模板时,编译器都必须为每种类型生成额外的代码。这是编译时多态性,它会随着你使用的次数而增加可执行文件的大小。如果从项目中排除STL(并且谨慎地使用模板或根本不使用),你的代码大小将变小。请注意,这不一定会更快。还要注意,我不是在谈论程序在执行期间的内存使用情况,因为这将取决于您在应用程序生命周期中分配多少对象。我说的是你的二进制可执行文件。如果你需要一个例子,请注意,一个简单的Hello world程序,在编译时可能比一个巧妙编写的demo更大,后者可以在非常小的可执行文件中包含整个3D引擎(运行时生成)。

关于uTorrent大小的一些信息:

官方FAQ(来自2008年),这个问题在最近的FAQ中没有出现。

uTorrent是如何被编程成如此高效的?

关于这个问题的第二篇帖子。

关于这个问题的第三篇帖子。

请注意,即使uTorrent>300kb并且使用UPX压缩,但考虑到它所能做的事情,它仍然非常小。


9
uTorrent的大小超过了300KB。我认为使用标准STL容器并不会有太大区别,特别是考虑到编写自己的容器也需要空间。 - Axel Gneiting
2
你应该解释一下STL为什么会导致代码膨胀——毕竟,仅仅包含它并不会增加二进制文件的大小... - Eamon Nerbonne
1
@PiotrLegnica:我认为darioo所说的是可执行代码大小而不是对象大小,因为模板可能会导致实例化爆炸,编译器通常会愉快地将它们内联,部分原因是为了增加执行速度(通常是大小/速度权衡),例如1MB可执行文件在当今的桌面上并不是问题。 - Fred Nurk
6
完全不同意这些评论:https://dev59.com/0XRC5IYBdhLWcg3wP-Zh。它获得了如此多的赞同票是令人不安的。 - Martin York
2
我看到最近我的答案遭到了很多批评。我还没有看到有令人信服的论据来解释为什么会出现这种情况。只是有很多术语上的吹毛求疵和一些链接,这些答案(在我看来)与我的答案并没有明显的不同。因此,如果有人在这个问题上拥有权威地位,我希望看到一篇引用了我的答案并指出哪些部分是如此明显错误以及正确的内容是什么的解答。 - darioo
显示剩余21条评论

3
我认为有时候您可能会因为需要更好的自定义,而在项目中某种情况下不使用STL的特定功能。STL集合通常是泛型的。 你可能希望在代码中使用以下内容: - 线程安全的无锁容器。(STL本身不是线程安全的。) - 通过引用复制实际数据的不可变字符串类(带有某些机制)。 - 高效的字符串构建类,不是ostringstream。(不属于STL,但您可能指所有标准库) - 使用Map和Reduce算法(不要与std::map混淆。 Map和Reduce是一种使用多个线程或进程迭代收集的方法,甚至可能分布在不同的机器上)。 嘿,看,Boost很大程度上是因为标准库在当时没有真正解决程序员的需求,因此提供了替代品。 我不确定这是否符合您的意思,或者您是否特别指出在任何时候都应该“禁止”STL(例如设备驱动程序设计,其中模板被认为是浪费空间的,尽管这并不总是情况)。

3
如果你在遵循特定的标准,禁止使用动态内存分配,例如MISRA C/C++ guidelines。这些标准针对汽车和嵌入式系统,因此你可能会选择完全避免使用STL容器。请注意:MISRA指南只是可能影响你选择使用STL的标准的一个例子。那个特定的指南并没有排除使用所有的STL,但(我相信)它排除了使用STL容器,因为它们依赖于运行时内存分配。

3
标准库容器不需要使用动态内存分配。您可以提供自己的分配器,以进行任何所需操作。尽管如此,标准分配器在某些领域存在问题,这些问题不易纠正,这在EASTL论文中最为明显。 - Fred Nurk
1
@GrahamS:stdlib容器不需要使用动态内存分配。它们使用自己的分配器来分配任何东西。 - Fred Nurk
1
@GrahamS:“动态内存分配”在C++中有着非常具体的含义,不同于“动态地”做某些事情。考虑一个循环,它读取用户输入并根据其动态执行操作。或者考虑“vector<int,MyAlloc> v(42);”:vector的构造函数执行的分配并不是我所知道的“动态”的,因为我确切地知道它将分配什么,以及从哪里分配。 - Fred Nurk
2
@GrahamS:您过于关注"runtime"和"memory"这些词;当新的大小小于当前容量时,push_back、resize、insert和reserve不涉及分配器。请考虑函数中的局部变量:函数调用会在运行时发生并需要内存,但这并非动态内存分配。 - Fred Nurk
1
@Graham:如果你有一个在堆栈上分配内存的分配器,你就会面临与本地变量相同的运行时“问题”。当然,它仍然发生在运行时,但是 - 那又怎样?如果你需要返回这样的东西 - 和 C 有什么区别呢?毕竟 C 在第一次就不允许这种情况。所以,这个论点也是无意义的。 - sbi
显示剩余19条评论

2

它可能会增加可执行文件的大小。如果你正在运行嵌入式平台,你可能希望排除STL。


2
它还可以减小可执行文件的大小。事先很难说。 - David Thornley
我确实使用了“可以”和“可能”的词语。 :) - tenpn

1

唯一的原因是,如果您正在使用内存较低的嵌入式系统工作,或者如果您的项目编码指南明确禁止STL。

我找不到其他合理的理由来手动滚动自己不兼容、错误满载的STL某些功能的实现。


1
嵌入式系统内存较低的情况下仍然可以使用STL的部分功能(例如std::copy和std::fill)。如果您没有足够的内存来使用STL,则可能在嵌入式系统上编写高级语言的空间也不足。 - Thomas Matthews

1

当您使用实现相同功能的Qt库等内容时,可能不需要STL。这可能取决于其他需求,例如性能。


0

TR18015讨论了STL的一些限制。它从不同的角度来看待问题——编译器能做得更好——但仍然是一个有趣(如果深入)的阅读。

总的来说,在微处理器和小型嵌入式系统中要小心。首先,编译器优化不如桌面计算机那么高效,而且你很快就会遇到硬件限制。

话虽如此,这在很大程度上取决于你使用的库。I/O流通常很慢(需要仔细实现才能避免),而std::vector只是一个薄薄的包装。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,