40

Unquestionably, I would choose to use the STL for most C++ programming projects. The question was presented to me recently however, "Are there any cases where you wouldn't use the STL?"...

The more I thought about it, the more I realized that perhaps there SHOULD be cases where I choose not to use the STL... For example, a really large, long term project whose codebase is expected to last years... Perhaps a custom container solution that precisely fits the projects needs is worth the initial overhead? What do you think, are there any cases where you would choose NOT to STL?

Judah Gabriel Himango
  • 55,559
  • 37
  • 152
  • 206
dicroce
  • 41,038
  • 26
  • 94
  • 136

15 Answers15

47

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.

Greg Rogers
  • 33,366
  • 15
  • 63
  • 93
  • 1
    This is what it comes down to. – Christopher Oct 06 '08 at 19:23
  • While I agree, I would also throw in concurrency as a reason not to use the containers. However, I would use them for any non-shared resource. – Matt Price Oct 07 '08 at 13:22
  • 6
    Greg - (1) is probably very uncommon, but (2) is highly situational. In certain development environments (e.g. embedded platforms and realtime systems), dynamic allocation is either forbidden or heavily discouraged. They may not be big environments, but within the environment it's universal. – Tom Dec 15 '08 at 01:59
  • @Tom: I always thought the average embedded program allocated all of its memory at the start. Why shouldn't you use STL containers for that? – Niki Oct 27 '09 at 18:27
  • 4
    Not wanting exceptions might be another reason not to use STL – sbk Oct 27 '09 at 18:32
  • You can also use the STL in cases where there is no dynamic memory allocation by just using your custom allocator. – Albert Sep 07 '10 at 00:31
  • 1
    @sbk: You can use the STL without exceptions. GCC at least implements `throw` as a macro that is defined to not actually throw when `-fno-exceptions` is set. – beldaz Nov 18 '10 at 23:01
  • Overlapping with STL is (mostly) only an issue if you're project relies on the STL in general. Would strictly and totally forbidding STL in your codebase not resolve this? I suppose external APIs relying on STL may present issues. – Philip Guin Oct 31 '13 at 17:15
31

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.

  • 2
    I always found that the SDL containers are all pretty lightweight. Check out your STL implementation to see how much memory they actually use. – Albert Sep 07 '10 at 00:34
  • Quite. If STL does what you want, use it. When it no longer does what you want, that's when you should consider not using it. – beldaz Nov 18 '10 at 23:04
  • `boost::array` and `boost::unordered_map` both exist in the STL now under the names of `std::array` and `std::unordered_map`. – L. F. Mar 23 '19 at 04:22
26

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.

Matt Price
  • 38,782
  • 9
  • 34
  • 43
  • 1
    Fixing container bugs is *fun*! I heartily disagree with assertion #2. (I do, however, strongly agree with #1 from a little experience.) – Philip Guin Oct 31 '13 at 17:17
15

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.

Evan Teran
  • 80,654
  • 26
  • 169
  • 231
6

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.

Trent
  • 12,321
  • 4
  • 36
  • 35
6

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.

coppro
  • 13,900
  • 3
  • 54
  • 73
5

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".

Steve Jessop
  • 257,525
  • 32
  • 431
  • 672
  • The Symbian API leads me to believe they understand neither C++ nor mobile software development. – MSalters Oct 07 '08 at 11:49
  • 1
    I won't particularly defend it, other than to say that it's 10 years or more old, and seems to have been designed for devices far more constrained than those it's actually used on. Even Nokia used S40 on their low-end devices, raising the question of why SymbianOS made the assumptions it did. – Steve Jessop Oct 07 '08 at 15:34
  • For example, on a 32MB RAM smartphone, as a programmer I'm not keen to do extra work in order to avoid a 4 bytes per string memory overhead. I guess that might have made sense at the time, though. And they treated C++ mostly as C with classes, which is unpopular these days. – Steve Jessop Oct 07 '08 at 15:39
4

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.

Nemanja Trifunovic
  • 23,597
  • 3
  • 46
  • 84
  • Why? Were you determined to use an old compiler that didn't work with STL? – beldaz Nov 18 '10 at 23:06
  • @beldaz: No. We had home-grown collection and string classes and mixing them with STL would make little sense. Rewriting everything to use STL would be nice in theory but there was no business case to support such project. – Nemanja Trifunovic Nov 19 '10 at 14:17
  • Interesting case, I can see where you're coming from. Not much you can do there. – beldaz Nov 20 '10 at 02:12
4

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.

Adrian Maire
  • 11,506
  • 8
  • 34
  • 72
3

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.

Caleb Huitt - cjhuitt
  • 14,132
  • 2
  • 40
  • 49
  • 2
    Given that STL is included as a standard part of C++, however, it's not so much that you don't add STL to your project but rather, you chose not to take advantage of something that is already there. Which is fine. – ChrisInEdmonton Nov 07 '09 at 16:17
2

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.

Ferruccio
  • 93,779
  • 37
  • 217
  • 294
Lou Franco
  • 83,503
  • 14
  • 127
  • 183
  • 1
    I don't understand. If your STL objects are not shared across threads, why would it matter whether or not an interlocked increment was used? – Ferruccio Oct 06 '08 at 14:35
  • 1
    Are you maybe using VC++ 6.0? That version has a broken STL implementation when it comes to thread safety. – Nemanja Trifunovic Oct 06 '08 at 14:42
  • Yes -- but that wasn't the only one. On Solaris and HP -- I ran into similar issues. – Lou Franco Oct 06 '08 at 15:45
  • Ferruccio -- create a string, then copy construct it and send it to another thread. They share a reference count. If I destruct the first string while the next thread is copy constructing it again, the reference count can be corrupted. – Lou Franco Oct 06 '08 at 15:46
  • So you *are* sharing STL objects across threads... – Steve Jessop Oct 07 '08 at 01:01
  • 1
    NO - read again. One object in one thread, a COPY in another thread. Two objects, two threads. Still a bug. The STL is part of standard C++, which has no threads. A threadsafe STL is a common vendor extension; with C++0x we'll expect no less. – MSalters Oct 07 '08 at 11:48
  • If you send a reference to an object from one thread (the one it was created in by copy) to another (where the copy is copied again), then you're sharing it between threads. In this case, doing so has messed up the copy-on-write behaviour, even though no one string object was concurrently accessed. – Steve Jessop Oct 07 '08 at 15:53
  • Btw, I'm not saying that STL is guaranteed safe in multi-threaded code provided you don't share STL objects between threads. I'm just saying that the described case was not an example of avoiding sharing STL objects, since it created an object in one thread and then accessed it from another. – Steve Jessop Oct 07 '08 at 16:45
  • 2
    The problem is the sharing is happening completely behind the string abstraction -- I can cause problems with strictly const strings and read-only operations -- because, internally, the strings share a reference count, just copy constructing (passing and returning strings) will cause the problem. – Lou Franco Oct 07 '08 at 16:47
2

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

Jamie Eisenhart
  • 170
  • 1
  • 5
1

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.

KPexEA
  • 15,698
  • 16
  • 57
  • 76
  • 3
    Just one question: Are you coding in C, or in C++ ? – paercebal Oct 07 '08 at 20:47
  • 4
    STL is not external code. It is a standard part provided by all standards-compliant C++ compilers. Given that your toolbox is apparently more than ten years out of date, it may be worth your time taking a look around and seeing what other advances have been made. Okay, I'm joking here, and I know EA has or had a justified aversion to STL. But you are mistaken in describing STL as "external". – ChrisInEdmonton Nov 07 '09 at 16:22
1

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.

1

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.

Community
  • 1
  • 1
Raedwald
  • 40,290
  • 35
  • 127
  • 207