由于在我之前回答的几乎每个人似乎都对 STL 容器如此热衷,我认为根据我自己遇到的实际问题编制一份不使用它们的充分理由列表会很有用。
这些可以合理地分为三大类:
1) 效率低
STL 容器通常运行速度较慢并且为作业占用过多内存。造成这种情况的部分原因可以归咎于底层数据结构和算法的过于通用的实现,额外的性能成本源自与手头任务无关的大量 API 要求所需的所有额外设计约束。
不计后果的内存使用和低劣的性能齐头并进,因为 CPU 以 64 字节的行在缓存上寻址内存,如果您不利用局部性引用来发挥自己的优势,那么您会浪费周期和宝贵的 Kb缓存内存。
例如,std::list 每个元素需要 24 个字节,而不是最佳的 4 个。
https://lemire.me/blog/2016/09/15/the-memory-usage-of-stl-containers-can-be-surprising/
这是因为它是通过打包两个 64 位指针、1 个 int 和 4 个字节的内存填充来实现的,而不是像分配少量连续内存并单独跟踪正在使用的元素或使用指针异或技术将两个迭代方向存储在一个指针中。
https://en.wikipedia.org/wiki/XOR_linked_list
根据您的程序需求,这些低效率可能而且确实会造成很大的性能损失。
2) 限制/爬行标准
当然,有时问题是您需要一些完全通用的函数或稍微不同的容器类,而这些容器类只是没有在 STL 中实现,例如优先级队列中的 reduce_min()。
一种常见的做法是,然后将容器包装在一个类中,并通过容器外部的额外状态和/或对容器方法的多次调用自己实现缺少的功能,这可能会模拟所需的行为,但性能要好得多比数据结构的实际实现更低且 O() 复杂度更高,因为无法扩展容器的内部工作。或者,您最终将两个或多个不同的容器混在一起,因为您同时需要两个或多个在任何给定 STL 容器中根本不兼容的东西,例如 minmax 堆、trie(因为您需要能够使用不可知论的指针) 等。
这些解决方案可能很丑陋,而且效率低下,但语言发展的趋势是只添加新的 STL 方法来匹配 C++ 的特性蔓延,并忽略任何缺失的核心功能。
3) 并发/并行
STL 容器不是线程安全的,更不用说并发了。在当今 16 线程消费 CPU 的时代,令人惊讶的是,现代语言的默认容器实现仍然需要您围绕每个内存访问编写互斥锁,就像 1996 年一样。对于任何非平凡的并行程序来说,这是一种重要的是,因为内存屏障会迫使线程序列化它们的执行,如果这些发生的频率与 STL 调用相同,那么您可以告别并行性能。
简而言之,只要您不关心性能、内存使用、功能或并行性,STL 就很好。
STL 当然仍然很好,因为很多时候您不受任何这些问题的约束,而可读性、可移植性、可维护性或编码速度等其他优先事项优先。