要STL还是!STL,这就是问题

发布于 2024-07-06 22:52:52 字数 1449 浏览 5 评论 0原文

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(15

反话 2024-07-13 22:52:52

不使用 STL 的主要原因是:

  1. 您的 C++ 实现很旧并且模板支持很糟糕。
  2. 您不能使用动态内存分配。

这两者在实践中都是非常不常见的要求。

对于长期项目来说,滚动自己的与 STL 功能重叠的容器只会增加维护和开发成本。

The main reasons not to use STL are that:

  1. Your C++ implementation is old and has horrible template support.
  2. You can't use dynamic memory allocation.

Both are very uncommon requirements in practice.

For a longterm project rolling your own containers that overlap in functionality with the STL is just going to increase maintenance and development costs.

天生の放荡 2024-07-13 22:52:52

具有严格内存要求的项目(例如嵌入式系统)可能不适合 STL,因为它可能很难控制和管理从堆中取出和返回到堆的内容。 正如 Evan 提到的,编写正确的分配器可以帮助解决这个问题,但如果您正在计算使用的每个字节或与内存碎片有关,那么手动推出针对您的特定问题量身定制的解决方案可能更明智,因为 STL 已经过优化对于最一般的用途。

您还可以选择在特定情况下不使用 STL,因为存在当前标准中未包含的更适用的容器,例如 boost::array 或 boost::unordered_map。

Projects with strict memory requirements such as for embedded systems may not be suited for the STL, as it can be difficult to control and manage what's taken from and returned to the heap. As Evan mentioned, writing proper allocators can help with this, but if you're counting every byte used or concerned with memory fragmentation, it may be wiser to hand-roll a solution that's tailored for your specific problem, as the STL has been optimized for the most general usage.

You may also choose not to use STL for a particular case because more applicable containers exist that are not in the current standard, such as boost::array or boost::unordered_map.

浪漫之都 2024-07-13 22:52:52

使用 stl 有很多优点。 对于长期项目来说,收益大于成本。

  1. 新程序员从第一天起就能够理解容器,这让他们有更多的时间来学习项目中的其他代码。 (假设他们已经像任何有能力的 C++ 程序员一样了解 STL)
  2. 修复容器中的错误很糟糕并且浪费了本可以用于增强业务逻辑的时间。
  3. 无论如何,您很可能不会像 STL 的实现那样编写它们。

话虽如此,STL 容器根本不处理并发性。 因此,在需要并发的环境中,我会使用其他容器,例如英特尔 TBB 并发容器。 这些使用细粒度锁定要先进得多,这样不同的线程可以同时修改容器,并且您不必序列化对容器的访问。

There are just so many advantages to using the stl. For a long term project the benefits outweigh the costs.

  1. New programmers being able to understand the containers from day one giving them more time to learn the other code in the project. (assuming they already know STL like any competent C++ programmer would)
  2. Fixing bugs in containers sucks and wastes time that could be spent enhancing the business logic.
  3. Most likely you're not going to write them as well as the STL is implemented anyways.

That being said, the STL containers don't deal with concurrency at all. So in an environment where you need concurrency I would use other containers like the Intel TBB concurrent containers. These are far more advanced using fine grained locking such that different threads can be modifying the container concurrently and you don't have to serialize access to the container.

小瓶盖 2024-07-13 22:52:52

通常,我发现最好的选择是将 STL 与自定义分配器一起使用,而不是用手工滚动的容器替换 STL 容器。 STL 的好处是您只需为使用的内容付费。

Usually, I find that the best bet is to use the STL with custom allocators instead of replacing STL containers with hand rolled ones. The nice thing about the STL is you pay only for what you use.

强辩 2024-07-13 22:52:52

我认为这是典型的构建与购买场景。 然而,我认为在这种情况下,在推出我自己的解决方案之前,我几乎总是会“购买”并使用 STL - 或更好的解决方案(可能来自 Boost)。 您应该将大部分精力集中在应用程序的功能上,而不是它使用的构建块上。

I think it's a typical build vs buy scenario. However, I think that in this case I would almost always 'buy', and use STL - or a better solution (something from Boost perhaps), before rolling my own. You should be focusing most of your effort on what your application does, not the building blocks it uses.

挽容 2024-07-13 22:52:52

我真的不这么认为。 在制作自己的容器时,我什至会尝试使它们与 STL 兼容,因为通用算法的威力太大了,无法放弃。 STL 至少应该在名义上被使用,即使您所做的只是编写自己的容器并为其专门化每个算法。 这样,每个排序算法都可以调用 sort(c.begin(), c.end())。 如果您专门排序以具有相同的效果,即使它的工作方式不同。

I don't really think so. In making my own containers, I would even try to make those compatible with the STL because the power of the generic algorithms is too great to give up. The STL should at least be nominally used, even if all you do is write your own container and specialize every algorithm for it. That way, every sorting algorithm can be invoked sort(c.begin(), c.end()). If you specialize sort to have the same effect, even if it works differently.

美煞众生 2024-07-13 22:52:52

Symbian 编码。

STLPort确实支持Symbian 9,所以反对使用STL的理由比以前弱了(“它不可用”是一个相当有说服力的理由),但STL对所有Symbian库来说仍然陌生,所以可能比仅仅更麻烦以 Symbian 方式做事。

当然,可能会基于这些理由争论 Symbian 编码不是“C++ 编程项目”。

Coding for Symbian.

STLPort does support Symbian 9, so the case against using STL is weaker than it used to be ("it's not available" is a pretty convincing case), but STL is still alien to all the Symbian libraries, so may be more trouble than just doing things the Symbian way.

Of course it might be argued on these grounds that coding for Symbian is not "a C++ programming project".

灼疼热情 2024-07-13 22:52:52

我参与过的大多数项目的代码库都比任何真正可用的 STL 版本都要老——因此我们选择现在不引入它。

Most of the projects I have worked on had a codebase way older than any really usable version of STL - therefore we chose not to introduce it now.

許願樹丅啲祈禱 2024-07-13 22:52:52

简介:

STL 是一个很棒的库,在很多情况下都很有用,但它绝对不能解决所有情况。 回答 STL 或 !STL 就像回答“STL 是否满足您的需求?”

STL 的优点

  • 在大多数情况下,STL 都有适合给定解决方案的容器。
  • 它有详细的文档记录
  • 它是众所周知的(程序员通常已经知道它,进入项目的时间较短)
  • 它经过测试并且稳定。
  • 它是跨平台的
  • 它包含在每个编译器中(不添加第三个库依赖项)
  • STL 已经实现并且准备就绪
  • STL 很闪亮,...

STL 的对比

您需要一个简单的并不重要图、红黑树或非常复杂的元素数据库,其中人工智能通过量子计算机管理并发访问。 事实是,STL 没有、也永远不会解决所有问题。

以下方面只是几个例子,但它们基本上是这个事实的结果:STL 是一个真正的库,有局限性。

  • 异常:STL 中继异常,因此如果出于任何原因您不能接受异常(例如安全关键),则不能使用 STL。 正确的! 异常可能会被禁用,但这并不能解决依赖它们的 STL 的设计问题,并且最终会导致崩溃。

  • 需要特定(尚未包含)的数据结构:图、树等。

  • 复杂性的特殊约束:您可能会发现 STL 通用容器对于您的瓶颈代码来说并不是最佳的。

  • 并发注意事项:要么您需要并发,但 STL 无法提供您所需要的(例如,由于双向 [] 运算符,读写器锁无法(轻松)使用)。 您可以设计一个利用多线程的容器,以实现更快的访问/搜索/插入/任何操作。

  • STL需要满足你的需求,但反之亦然:你需要满足STL的需求。 不要尝试在具有 1K 非托管 RAM 的嵌入式微控制器中使用 std::vector

  • 与其他库的兼容性:可能由于历史原因,您使用的库不接受STL(例如QtWidgets大量使用它自己的QList)。 双向转换容器可能不是最好的解决方案。


实现您自己的容器

读完后,您可能会想:“好吧,我确信我可以为我的具体情况做一些比 STL 更好的事情。”等等!

正确实现容器很快就会成为一项艰巨的任务:它不仅仅是实现一些有效的东西,您可能必须:

  • 深入记录它,包括限制、算法复杂性等。
  • 期待错误,并解决它们
  • 传入的额外需求:你知道,这个函数缺失,类型之间的转换等等。
  • 过了一段时间,你可能想要重构,并更改所有依赖项(太晚了?)
  • ...

在代码深处使用的代码(如容器)绝对需要时间来实现,并且应该仔细执行。


使用第3方库

不是STL并不一定意味着定制。 网络上有很多好的库,有些甚至拥有宽松的开源许可证。

添加或不添加额外的第三方库是另一个话题,但值得考虑。

Introduction:

STL is a great library, and useful in many cases, but it definitively don't solve all the situations. Answering STL or !STL is like answering "Does STL meet your need or does it not?"

Pros of STL

  • In most situations, STL has a container that fit for a given solution.
  • It is well documented
  • It is well known ( Programmers usually already know it, getting into a project is shorter)
  • It is tested and stable.
  • It is crossplatform
  • It is included with every compiler (does not add a 3rd library dependency)
  • STL is already implemented and ready
  • STL is shiny, ...

Contras of STL

It does not mater that you need a simple Graph, Red-Black Tree, or a very complex database of elements with an AI managing concurrent access through a quantum computer. The fact is, STL do not, and will never solve everything.

Following aspects are only a few examples, but they basically are consequence of this fact: STL is a real library with limits.

  • Exceptions: STL relay on exceptions, so if for any reason you cannot accept exceptions (e.g. safety critical), you cannot use STL. Right! exceptions may be disabled, but that does not solve the design of the STL relaying on them and will eventually carry a crash.

  • Need of specific (not yet included) data structure: graph, tree, etc.

  • Special constraints of complexity: You could discover that STL general purpose container is not the most optimal for your bottleneck code.

  • Concurrency considerations: Either you need concurrency and STL do not provide what you need (e.g. reader-writer lock cannot(easily) be used because of the bi-directional [] operator). Either you could design a container taking benefit of multi-threading for a much faster access/searching/inserting/whatever.

  • STL need to fit your needs, but the revers is also true: You need to fulfill the needs of STL. Don't try to use std::vector in a embedded micro-controller with 1K of unmanaged RAM.

  • Compatibility with other libraries: It may be that for historical reasons, the libraries you use do not accept STL (e.g. QtWidgets make intensive use of it own QList). Converting containers in both directions might be not the best solution.


Implementing your own container

After reading that, you could think: "Well, I am sure I may do something better for my specific case than STL does." WAIT!

Implementing your container correctly become very quickly a huge task: it is not only about implementing something working, you might have to:

  • Document it deeply, including limitations, algorithm complexity,etc.
  • Expect bugs, and solving them
  • Incoming additional needs: you know, this function missing, this conversion between types, etc.
  • After a while, you could want to refactor, and change all the dependencies (too late?)
  • ....

Code used that deep in the code like a container is definitively something that take time to implement, and should be though carefully.


Using 3rd party library

Not STL does not necessarily mean custom. There are plenty of good libraries in the net, some even with permissive open-source license.

Adding or not an additional 3rd party library is another topic, but it worth to be considered.

白云悠悠 2024-07-13 22:52:52

可能发生这种情况的一种情况是,当您已经在使用已经提供了 STL 所需功能的外部库时。 例如,我的公司在空间有限的领域开发了一个应用程序,并且已经使用 Qt 作为窗口工具包。 由于 Qt 提供了类似 STL 的容器类,因此我们使用它们而不是将 STL 添加到我们的项目中。

One situation where this might occur is when you are already using an external library that already provides the abilities you need from the STL. For instance, my company develops an application in space-limited areas, and already uses Qt for the windowing toolkit. Since Qt provides STL-like container classes, we use those instead of adding the STL to our project.

葬シ愛 2024-07-13 22:52:52

我发现在多线程代码中使用STL存在问题。 即使您不跨线程共享 STL 对象,许多实现也会使用非线程安全构造(例如用于引用计数的 ++,而不是互锁增量样式,或者具有非线程安全分配器)。

在每种情况下,我仍然选择使用 STL 并解决问题(有足够的钩子来获得你想要的东西)。

即使您选择创建自己的集合,遵循迭代器的 STL 风格也是一个好主意,这样您就可以使用仅在迭代器上运行的算法和其他 STL 函数。

I have found problems in using STL in multi-threaded code. Even if you do not share STL objects across threads, many implementations use non-thread safe constructs (like ++ for reference counting instead of an interlocked increment style, or having non-thread-safe allocators).

In each of these cases, I still opted to use STL and fix the problems (there are enough hooks to get what you want).

Even if you opt to make your own collections, it would be a good idea to follow STL style for iterators so that you can use algorithms and other STL functions that operate only on iterators.

墨离汐 2024-07-13 22:52:52

我看到的主要问题是必须与依赖于非抛出运算符 new 的遗留代码集成。

The main issue I've seen is having to integrate with legacy code that relies on non-throwing operator new.

星軌x 2024-07-13 22:52:52

我大约在 1984 年左右开始 C 语言编程,从未使用过 STL。 多年来,我推出了自己的函数库,当 STL 尚未稳定或缺乏跨平台支持时,它们已经发展和壮大。 我的公共库已经发展到包含其他人的代码(主要是 libjpeg、libpng、ffmpeg、mysql )和其他一些人的代码,我宁愿将其中的外部代码量保持在最低限度。 我确信现在 STL 很棒,但坦率地说,我对工具箱中的项目很满意,并且认为目前没有必要为其加载更多工具。 但我确实看到了新程序员可以通过使用 STL 实现巨大的飞跃,而无需从头开始编写所有代码。

I started programming C back in about 1984 or so and have never used the STL. Over the years I have rolled my own function librarys and they have evolved and grown when the STL was not stable yet and or lacked cross platform support. My common library has grown to include code by others ( mostly things like libjpeg, libpng, ffmpeg, mysql ) and a few others and I would rather keep the amount of external code in it to a minimum. I'm sure now the STL is great but frankly I'm happy with the items in my toolbox and see no need at this point to load it up with more tools. But I certainly see the great leaps and bounds that new programmers can make by using the STL without having to code all that from scratch.

薄荷梦 2024-07-13 22:52:52

标准 C++ 反常地允许某些迭代器操作的实现抛出异常。 在某些情况下,这种可能性可能会产生问题。 因此,您可以实现自己的简单容器,保证不会抛出关键操作的异常。

Standard C++ perversely allows implementations of some iterator operations to throw exceptions. That possibility can be problematic in some cases. You might therefore implement your own simple container that is guaranteed not to throw exceptions for critical operations.

红颜悴 2024-07-13 22:52:52

由于几乎所有在我之前回答的人似乎都对 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/< /a>

这是因为它是通过打包两个 64 位指针、1 个 int 和 4 个字节的内存填充来实现的,而不是执行像分配少量连续内存并单独跟踪正在使用的元素或使用指针异或技术将两个迭代方向存储在一个指针中。

https://en.wikipedia.org/wiki/XOR_linked_list

根据您的程序需求,这些效率低下确实会造成巨大的性能损失。

2) 限制/蠕变标准

当然,有时问题是您需要一些完全通用的函数或略有不同的容器类,但这些函数未在 STL 中实现,例如优先级队列中的decrease_min()。

一种常见的做法是将容器包装在一个类中,并使用容器外部的额外状态和/或对容器方法的多次调用来自己实现缺少的功能,这可能会模拟所需的行为,但性能要低得多,并且 O () 的复杂性高于数据结构的实际实现,因为无法扩展容器的内部工作方式。 或者,您最终会将两个或多个不同的容器混合在一起,因为您同时需要两个或多个在任何给定的 STL 容器中根本不兼容的东西,例如最小最大堆、特里树(因为您需要能够使用不可知指针) )等。

这些解决方案可能很丑陋,而且还会带来其他效率低下的问题,但语言发展的趋势是仅添加新的 STL 方法来匹配 C++ 的功能蔓延,并忽略任何缺失的核心功能。

3)并发/并行

STL容器不是线程安全的,更不用说并发了。 在当今 16 线程消费者 CPU 的时代,令人惊讶的是现代语言的首选默认容器实现仍然要求您像 1996 年一样在每次内存访问周围编写互斥体。对于任何重要的并行程序来说,这都是一种这很重要,因为内存屏障会强制线程序列化它们的执行,如果这些发生的频率与 STL 调用相同,那么您就可以告别并行性能了。

简而言之,只要您不关心性能、内存使用、功能或并行性,STL 就很好。
当然,当您不受任何这些问题的约束并且其他优先事项(例如可读性、可移植性、可维护性或编码速度)优先时,STL 仍然非常好。

Since almost everybody who answered before me seemed so keen on STL containers, I thought it would be useful to compile a list of good reasons not to use them, from actual problems I have encountered myself.

These can be reasonably grouped into three broad categories:

1) Poor efficiency

STL containers typically run slower AND use too much memory for the job. The reason for this can be partly blamed on too generic implementations of the underlying data structures and algorithms, with additional performance costs deriving from all the extra design constrains required by the tons of API requisites that are irrelevant to the task at hand.

Reckless memory use and poor performance go hand in hand, because memory is addressed on the cache by the CPU in lines of 64 bytes, and if you don't use locality of reference to your advantage, you waste cycles AND precious Kb of cache memory.

For instance, std::list requires 24 bytes per element rather than the optimal 4.

https://lemire.me/blog/2016/09/15/the-memory-usage-of-stl-containers-can-be-surprising/

This is because it is implemented by packing two 64-bit pointers, 1 int and 4 bytes of memory padding, rather than doing anything as basic as allocating small amounts of contiguous memory and separately tracking which elements are in use, or using the pointer xor technique to store both iteration directions in one pointer.

https://en.wikipedia.org/wiki/XOR_linked_list

Depending on your program needs, these inefficiencies can and do add up to large performance hits.

2) Limitations / creeping standards

Of course, sometimes the problem is that you need some perfectly common function or slightly different container class that is just not implemented in STL, such as decrease_min() in a priority queue.

A common practice is to then to wrap the container in a class and implement the missing functionality yourself with extra state external to the container and/or multiple calls to container methods, which may emulate the desired behavior, but with a performance much lower and O() complexity higher than a real implementation of the data structure, since there's no way of extending the inner workings of the container. Alternatively you end up mashing up two or more different containers together because you simultaneously need two or more things that are fundamentally incompatible in any one given STL container, such as a minmax heap, a trie (since you need to be able to use agnostic pointers), etc.

These solutions may be ugly and add on top of the other inefficiencies, and yet the way the language is evolving the tendency is to only add new STL methods to match C++'s feature creep and ignore any of the missing core functionality.

3) Concurrency/parallelism

STL containers are not thread-safe, much less concurrent. In the present age of 16-thread consumer CPUs, it's surprising the go-to default container implementation for a modern language still requires you to write mutexes around every memory access like it's 1996. This is, for any non-trivial parallel program, kind of a big deal, because having memory barriers forces threads to serialize their execution, and if these happen with the same frequency as an STL call, you can kiss your parallel performance goodbye.

In short, STL is good as long as you don't care about performance, memory usage, functionality or parallelism.
STL is of course still perfectly fine for the many times you are not bound by any of these concerns and other priorities like readability, portability, maintainability or coding speed take precedence.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文