[This page is completely misnamed, since most critique is directed at parts of the c++ standard library that do not belong to STL or at shortcomings of the CeePlusPlus
As the following comments show, a short explanation as to the purpose of this "rant" is needed. The StandardTemplateLibrary
is often lauded as the jewel of the CeePlusPlus
language. While it is true that sort, lower_bound, and map make everyone's life simpler, some features are hmmm less successful. This page is intended to raise the level of critical understanding of STL, and the level of expectations one should have for a generic programming solution and the challenges it raises for C++.
A good way to understand how StandardTemplateLibrary
got in its current state lies in its history:
- STL has kept changing all the time, headers changing name, declarations hidden into a std namespace. Obviously, the guys who first worked on STL were under some pressure to show that "productivity increases 10-folds with SilverBullet, ha, err, C++", rather than getting things right
- Latest 98 CppStandard shows that people understood the trouble and damage wrecked by constant fiddling (fumbling) with the language specs. It looks like that, at last, put an end to all these STL spec changes. Which means that a piece of standard C++ compliant code might last for more than 5 years.
It also means that nothing useful comes from STL anymore (the good stuff would come from, say, the BoostLibraries
), what you get with STL is a controversial pile of bad code frozen (something akin to LavaFlow
) from the time when the C++ dinosaurs were roaming the earth.
Defects in the StandardTemplateLibrary
that are symptomatic of its origins are:
- auto_ptr is a joke, it had to be redesigned several times, and still does not look nearly as serious as a good boost shared pointer (BoostSharedPtr).
- Err, no hashmap, StlPort anyone?
- iostream does not bring new functionality compared to C (e.g., still no UniCode support), specifying format is harder than in C, some compiler implementations had problems with sstream/stringstream. This is just a case where someone proposed some syntactic sugar to make demo code look nicer. An even more obvious example of this is the stream_iterator
- "Generic programming" from <functional> is a joke, if you manage to use something once, you get overcome with remorse that no-one will ever be able to debug your code.
- Iterators are complex to define when implemented on a programmer defined container (as opposed to STL container defined operator), as many redundant operations need to be there before one can call a given algorithm (think random iterator)
- STL Code is undebuggable (try reading through the values in a map, or a list in a debugger), it is even sometimes unreadable the functional binder1st provide a byzantine example of WriteOnlyCode.
- Performance of vector provided as standard on vc++ sucks. Well, the solution of this particular problem could be to install StlPort. Still I take that as an indication that this standard is complex to implement
- Early Adopters did get burned
- Many features in STL are best left unused
- STL is the lowest common denominator. Good Development in generic programming come from other sources
- Code is generally very hard to debug. Programmers should be acutely aware of this
- Some implementations of STL are not as good as others (you have been warned)
STL has kept changing all the time, headers changing name, declarations hidden into a std namespace. Obviously, the guys who first worked on STL were under some pressure to show that "productivity increases 10-folds with SilverBullet, ha, err, C++", rather than getting things right
Latest 98 CppStandard shows that people understood the trouble and damage wrecked by constant fiddling (fumbling) with the language specs. It looks like that, at last, put an end to all these STL spec changes. Which means that a piece of standard C++ compliant code might last for more than 5 years. It also means that nothing useful comes from STL anymore (the good stuff would come from, say, the BoostLibraries), what you get with STL is a controversial load of dung frozen from the time when the C++ dinosaurs were roaming the earth
Err, no hashmap, StlPort anyone?
No argument - except that STL wasn't even originally part of the C++ language. It originates before 1980, when it was written in Ada, and was only officially added to C++ in 1994. Considering that C++ itself wasn't even finalized until 1998, this isn't surprising at all. It does take a while for new things to get added to the language (and no, it hasn't even happened yet - however, they are reportedly planning to add hash_map.)
- Very interesting, thanks for the history. I thought you must surely be wrong, since the first Ada compiler wasn't completed until 1985 (I checked), but nonetheless apparently STL did begin as a generic programming project for Ada in 1979, written against the standard, despite the lack of a compiler (http://www.sci.tamucc.edu/~jfernand/cs5330/lectures/ch2.pdf). Released as Ada library 1987, implementation switched to C++ in 1990.
And I don't really see what it has to do with STL today, for that matter. I don't care about the history, I'd rather look at what it brings me *now*.
iostream does not bring new functionality compared to C (e.g., still no UniCode support), specifying format is harder than in C, some compiler implementations had problems with sstream/stringstream. This is just a case where someone proposed some syntactic sugar to make demo code look nicer. An even more obvious example of this is the stream_iterator
Again, no argument - but iostream isn't even part of the STL! The STL only contains data structures and algorithms, data IO is simply part of the C++ standard library. There are some supplied objects to make iostreams more compatible with the bulk of the STL (for example stream_iterator, which I have never once used) but all they share beyond that is a reliance on templates and some of the same design styles.
auto_ptr is a joke, it had to be redesigned several times, and still does not look nearly as serious as a good boost shared pointer (BoostSharedPtr).
"Generic programming" from <functional> is a joke, if you manage to use something once, you get overcome with remorse that no-one will ever be able to debug your code. Look at the BoostLambdaLibrary for more AdultEntertainment?
- auto_ptr does something completely differnet to shared_ptr, granted there are porbably more places where a shared_ptr is useful then there are places an auto_ptr is but there are places that auto_ptr is exactly what you want
Once again, no argument on either of these - but pointing out parts of the library that aren't terribly useful says nothing about the rest of it. By that logic, Java is the worst language on the planet, just because its library is so gigantic. I'm never going to touch use nine tenths of it - if not more - but that says nothing about the parts that are actually useful.
Performance of vector provided as standard on vc++ sucks. Well, the solution of this particular problem could be to install StlPort. Still I take that as an indication that this standard is complex to implement
One complaint: you didn't specify which version of VisualCeePlusPlus
you tried. For example, I found that version 6.0's STL had some real performance and just plain implementation issues, so we moved to StlPort
. When we upgraded to version 7.0, we tried substituting their allegedly-better version of Stl and dumped StlPort
, and the performance of basic_string ran circles around StlPort
's (most likely due to new a performance hack in small string allocation). -- TimLesher
Oh, and performance on specific compilers doesn't say anything about the specification's quality either, especially when there's a substitute for the library that fits seamlessly :P Just the existence of a perfectly good implementation shows that it's possible to do, and as far as I'm concerned, that's enough. Amusingly, I got to this page from XmlSucks
, which has almost this exact argument - without the existence of a fast implementation to nullify it.
Iterators are complex to define when implemented on a programmer defined container (as opposed to STL container defined operator), as many redundant operations need to be there before one can call a given algorithm
This isn't nearly as hard as you're indicating - for a forward iterator you need to implement exactly three methods, one of which can be implemented in terms of another. A bidirectional iterator takes about twelve, many of which can be done in one line by referring to others. Most of the complexity is probably whatever is necessary to deal with your underlying data structure.
On the other hand, it *would* be nice if those semi-redundant functions would just sort of happen on their own. One (rather ugly) solution can be done with inheritance and a base class (and yes, this is possible without virtual functions, just tricky). But it's not nearly as intuitive as it could be.
STL Code is unreadable/undebuggable, another example of WriteOnlyCode.
This I highly disagree with. In my current project I'm using quite a lot of STL, and I can't think of any that isn't completely readable.
vector is identical to array for normal use, and includes .size() to find out how large it is. .resize() resizes it, and if you don't know how large it's going to be, you can also use .push_back() to add elements to the back and resize at the same time. In places where I'm not using any of those functions I have occasionally had to find the variable's definition to figure out whether I defined it as an array or a vector - if I want to change from one to the other, it's rarely more than a few minutes' work.
map is, if anything, easier - use array semantics for associative-array lookups and the .count() member function to see if an element exists. Which you don't even have to do most of the time, since if an element doesn't exist, it will be automatically created.
The sort function is obvious, even when applied to arrays and not vectors. random_shuffle is equally obvious. In fact, the least intuitive thing I've seen is unique(), which has some unfortunate quirks due to the standard STL semantics.
I will cheerfully admit that I have plenty of unreadable code in some areas of this project - however, it's invariably in spite of STL, not because of it.
While I'd love to go on forever about how great STL is, I will point out that it has plenty of limits. I very rarely make my own STL containers - most of the time when I need a container, its semantics are different enough from STL's that shoehorning it into place makes no sense. (My most recent container can be best described as a sparse 2d array, and I don't even want to think about what an iterator on it would act like.) Like most libraries, I've found the best policy to be "use it when it works, don't use it when it doesn't" - I've just found *very* few things that it doesn't work with.
I'd love to hear any disagreements, but I've been using STL for several years now and have never had real issues with it, besides nonconformant compilers (trying to use some of the cooler features on MSVC++6 is painful, although they work beautifully on MSVC.NET.)
Hmmm... the first section is almost entirely irrelevant or inaccurate.
Like many people, I find the STL very useful and portable in practice.
Perhaps what's missing here is any kind of idea as to what the original writer might want instead of the STL. There are some areas where the STL is clearly not everything one might want. But a blanket rant like this doesn't really help anyone at all.
Is there any point to even keeping this page up? Something like StlIsNoGoodForFunctionalProgramming?
might bear more fruit - as it is, I can't see much benefit...
-- [removed name, I'm no longer signing contributions]
I don't know, a spot of trolling on the Wiki at least brings out the facts for the record. The STL is of course great, despite a few minor failings (mainly not those mentioned above). Compared to other languages, STL containers don't lose the type information of their contents, and compared to other libraries, the STL containers are exception-safe. Naturally, the challenge to anyone who claims it "sucks" is to do better themselves. How about starting with something simple, like ooh... auto_ptr? Actually, I can't think of a single part of the STL which I could redesign anywhere near as well. Mentions of the BoostLibraries
are welcome though, since it's more of the same, and of a similar standard. Where boost surpasses the STL, well, that's progress for you. Oh, as for "undebuggable", that's implementation dependent, surely. If it bothers you, donate some work to making STLport easier to debug. -- AnAspirant
One of the reasons the STL is often called "undebuggable" is that due to limitations in the C++ template mechanism; errors in template declarations are often reported deep within the bowels of the template definition, not at the point where the user issues an erroneous declaration. This isn't really the fault of the STL. (GCC 3.4 reports the usage point too.
) A couple ProposedAdditionsToCeePlusPlus
that might help:
- template typedefs, i.e. the ability to do "template<class T> typedef Foo<T,int> Bar" which declares Bar<T> to be an alias for Foo<T,int>. One of the best uses of typedef in C++ is to simplify long and complicated STL declarations.
- BoundedPolymorphism, i.e. EffBoundedPolymorphism?. Java is getting this in 1.5, which will make Java's template mechanism arguably more powerful than C++
- A "require" (or choose a better name) statement, used for compile-time assertions. Similar to #if !(blah) #error, but which works at the language level, not at the preprocessor level. If a require directive is placed within a template definition, its effect is delayed until the template is expanded. Intelligent use of such a directive would allow more intelligent STL error messages to be issued.
The reason for the rant, or the reason for this stlsucks page, is because some person wants to have unlimited possibilities. When you are unlimited (no structure, no standard), nothing gets done. Imagine using a simple text editor with no features on it. Standard means limit, and structure. Structure is good because:
-If your mouse and keyboard was different from everyone else's, you'd have to design your own keyboard. Do you have a factory in your house to do this?
-if everyone had to make their own OS, since there was no standard, would anything get done?
I've had several sharp discussions with current coworkers, and even the 'chief architect', over why STL DOES NOT SUCK.
One developer hates it because error messages are too hard to figure out. Another hates it because Microsoft started enforcing the use of standard dot-h-less headers, and this broke some 3rd party (non standard compliant API that was using STL). Another hates it because the template compiler takes up too much time. The 'chief architect' doesn't like it because it's not a cross platform standard; you read me right, our C++ architect is actually that ignorant.
So instead, everyone writes their own proprietary containers that nobody else can possible make use of. They prove their superiority over the standard library writers by creating their own link list, and say, "ah ha, I can do what STL does", but then spend weeks scratching their heads trying to figure out how to write a priority queue or binary search tree. They handle their own cross platform issues to the best of their limited knowledge, and then throw it to the MAC guy to deal with the actual port.
Instead of getting over the trivial issues they have with STL, they redo the basics of containers and algorithms every time, wasting time and money in the process. But hey, at the end, we get to replace "Sucky STL" with their AWESOME code. I pity the code maintainer.
Sorry, Dru here, and I agree with the original poster. To me, the question is really this? Have you been exposed to a better system? If you had been, I think you would see where this guy is coming from. It is the reason that there are a growing number of C#/Java/Perl/Python/PHP/etc. programmers versus C++ programmer. When I get a std data structures library, I want to do something like:
for_each(string key; myMap)
operator() (yada yada yada)
for_each(myMap.begin(), myMap.end(), MapOps);
- Oh come on! STL is innocent here, C++ is just lacking lambda. With the BoostLambdaLibrary it's a one liner.
Also, iterators are a terrible oppression on C++ programmers.
map<string, someComplexObject> myMap;
map<string, someComplexObject>::iterator myMapIter;
for (myMapIter = myMap.begin(); myMapIter != myMap.end(); ++myMapIter)
// hmm.. maybe I should have used 'i'??
// whew, lots of typing... but was worth it... I feel safer with these concrete shoes
- You know, you could have used a typedef. You could also have used for_each and wouldn't have to declare the iterator types. And what's that printf business doing here? iostreams are more extensible and puts would have done the job in your case anyway.
OR how about this design??
if (myMap.find("rUhere") == myMap.end())
couldn't just do the: bool myMap.has_key()
and why is this important?
because this myMap["rUhere"] ALWAYS INSERTS!?!?!?!
- Errm... you don't happen to know what else it could do? Return a null reference or what? And again, if has_key is sooo important to you, it's a one liner again. Templated, of course, so it also works on other maps and even other containers.
"hey druster, why not just make those improvements?"
Why? Because the language should do this for us, so we are all not reinventing the wheel. Luckily C++ is not the only language to have this problem.
Could C++ make people in the C#/Java/etc. crowd happy? Yes, they probably could have.
Dru: Walter Bright got tired of C++/STL (or something like that) and made D http://www.digitalmars.com/d
. It "corrects" many of the problems you point out about STL. See DeeLanguage
The thing that annoys me the most about the STL is lack of polymorphism and OO design.
It's a functional design, of course it's not OO, it's also loaded with polymorphism so not sure what you mean there.
Imagine you had a project where several classes had to work with collections or return them as arguments. In Java or C#, you'd use the Collection class. In C++/STL, you'd have to have template<type Iterator> methods that take a begin and end for all the methods that require parameters, and there would be no way to return a collection other than a pair of iterators. Furthermore, there would be no way to require that a method is given, say, a bidirectional iterator - you'd just write the code and get a compile-time error if operator-- isn't defined on the iterator. This is not just an annoyance, it can lead to serious problems; say you had a method that has to work a bidirectional or random iterator logically, but your first implementation was an inefficient version using only the forward-access commands of the iterator; and your coworker wrote 20 classes which pass in forward-only iterators to this method; now you implement a more efficient algorithm, and code in a completely different part of the program breaks apart.
Templates are nice, but depending only on templates to create a polymorphic library is the wrong way to go.
Lack of polymorphism? Are you kidding? STL is highly polymorphic. You have more of a point on "OO design", which leads me to think that you consider SubtypePolymorphism? the only kind worth having. Some of your other arguments are a rehash of those found in LatentTypesSmell.
- You can return collections from methods, it's just often a bad idea. You can also return a pair<iterator,iterator> if the usual team of begin/end is for some reason unsuitable. You can have multiple pairs of begin/end under different names, should you want to expose multiple internal classes. If you usually pass whole collections and the iterator pair seems cumbersome, write some template functions that call begin/end for you, but then don't whine that you cannot pass subsequences any more. And you can even specialize algorithms for different iterator categories, so they are both efficient for random access iterators and work with forward iterators. The standard library does this with std::advance and some others. You can do lots of things, you just have to learn them. "I hate STL b/c is dies things different from what I'm used to" is a somewhat weak argument...
Much of the above confuses the STL with the C++ standard library (i.e. comments about auto_ptr, iostreams, hash_map, etc...) StlIsNotTheCppStandardLibrary
, people. One shouldn't criticize one for the sins of the other.
One of the undebuggable
things in STL, is, ...
Say I have a list, or a vector, of strings. There are 5 items in the list. How do I see these in the debugger?
If I use std::string, it's okay, I can see all of them.
If I use std::list<std::string>, or std::vector<std::string>, now I can't
How irritating! I'll just put up with a MAX_STRINGS limit, with the benefit of finally being able to see my data while I'm debugging.
While I have my share of qualms about STL, this I blame on the debugger. A good debugger should allow you to provide your own display function, perhaps leveraging the 'operator << (std::ostream&,const T&)' if one exists in the linked executable.
In most of these cases, we're not interested in "Who do we blame?" But rather, "Does it work?"
And since we can't see into STL lists and maps in our (admittedly flawed debuggers,) then the argument that "code that uses STL can't be debugged easily" continues to stand.
Yes, perhaps the debugger is to blame. But I've still got a job to do. -- LionKimbro
I'm far from a huge C++ advocate, and, as has been pointed out, this has to do with the C++ standard library and not the STL, but I feel compelled to respond to this critique, which was posted way up there:
iostream does not bring new functionality compared to C (e.g., still no UniCode support), specifying format is harder than in C, some compiler implementations had problems with sstream/stringstream. This is just a case where someone proposed some syntactic sugar to make demo code look nicer.
This is nonsense. Streams do
bring new functionality to C++: you can use ResourceAcquisitionIsInitialization
(RAII) with iostreams, and you can overload operator<< and operator>> to allow custom data types to be written to streams. By contrast, printf, fprintf, etc. are not customizable at all. You could argue that these things are not really necessary (although I think the RAII point is a very good one since it's the C++ way of doing things), and technically that's true, but you can't just claim that they bring no new functionality at all. - Kef Schecter (FurryKef
Everyone forgot to add that allocators are a joke.
It all looks fine on paper until you actually try to use them. std::string with default allocator is a different type than std::string with my custom allocator. Result: forget about stringstream use, forget about runtime_error(string) constructor and myriad of other things that have std::string in their signature. Nothing works with it - it's just alien to the system.
C++ would be a wonderful language - if only it had a proper standard library!!!
C++ is fast, often faster than C because of templates.
C++ could be safe and robust, if used with appropriate tools (which do not exist unfortunately)
C++ is amazingly expressive, nothing else mainstream comes even close.
C++ language (not library) has only 1 problem that bothers me: templates cannot be separately compiled. This sucks and makes them only half (or quarter) as useful.
This all goes to waste, because there is no standard library to speak of!
What we have is a bunch of mis-fitting features developed in the 80s, that pretend to work.
Take std::string for example.
Obviously, it is impossible to create a single string type that would perform good in a wide range of use scenarios. Especially a string type that tries to do so much as std::string. So what we get is amazingly slow, Swiss Army knife piece of junk. It's only good for toy programs.
If I was after such string, I would not use C++ in the first place. I'd go and use C# or Java - they have much better strings. They are better because:
- they are safer (forget about crashes)
- they compile faster
- they run faster (benchmark C# System.String against std::string - it's like a Blackbird against Sopwith Camel)
- they have more complete interfaces
When we are at string interfaces. Every time I use std::string it simply kills me that I have to write my own:
- you name it - there's plenty more
Actually you don't have to write your own. All these operations you name are provided by the BoostStringAlgorithmsLibrary, one of the BoostLibraries.
Someone please start a massive project on SourceForge
to write a cross-platform C++ standard library replacement (using CeePlusPlusZeroEx
(C++0x) features). Model it e.g. on .NET. This is the only way to save C++. Otherwise it will go out of mainstream use within several years.
See for current perspectives TheCppStandardsCommittee
See also: AlexanderStepanov