To STL or !STL, that is the question [closed] - c++

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 3 years ago.
Improve this question
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?

The main reasons not to use STL are that:
Your C++ implementation is old and has horrible template support.
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.

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.

There are just so many advantages to using the stl. For a long term project the benefits outweigh the costs.
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)
Fixing bugs in containers sucks and wastes time that could be spent enhancing the business logic.
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.

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.

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.

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.

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

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.

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.

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.

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.

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

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.

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.

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.

Related

Should I use Standard C++ Containers and Stuff for games and other real time activities?

I'm a C++ developer using VS 2012 and VS 2010 for developing AAA titles. I have read about not using STL and other stuff provided in the standard headers that come with VS. I read most of the stuff on the websites based on game programming and some are really from the people well known in the industry. I have seen cases where they wont even use vector, list, map and others and not even use utility functions and algorithms. In such cases they write those containers and stuff themselves which has almost the same interface and so much of debug and implementation time spent on such huge code.
I have two questions:
1: Isn't the C++ implementation that comes with VS optimized for the platform for better performance? Isn't it using some intrinsic functions that people on the client end doesn't know about and supplying their own implementation would indeed be more slower in basic container operations such as insert, remove, find, swap, copy? Lets assume that we supply our own custom allocators for faster memory management to every container that we use. Also, they take care of fragmentation, alignment and stuff. Why develop custom containers with almost same interface, why not spend that time on writing allocators and other stuff that might actually help?
2: There are times when we include a lot, a lot, of unnecessary stuff through the standard headers in a huge code base. Unnecessary, because we only needed a thing or two from such huge headers including other huge headers and so on. Now, I know templates aren't instantiated unless used, same goes for the members functions inside them and blah blah. Since, these are precompiled headers, it is safe to assume that there is no compile time hit for that unnecessary stuff. My question is, is there any hidden effect of such inclusions on code size (executable) that grows with the huge growth of the code base? In my opinion there shouldn't be, but I wanna know I'm not mistaken just in case.
Thanks
The STL is optimized for performance for general computing. Many applications have specific characteristics which can be leveraged to improve performance (though perhaps only slightly) beyond what's offered by a fully general solution. At the same time, many people do write their own containers and end up with worse performance because they didn't understand the problem well enough, or have bugs that are never found due to limited testing (relative to most STL implementations which receive near infinite testing).
No, there is not generally any detriment to runtime performance simply from including lots of header files.
Apart from your specific questions, if you are developing AAA games, you should look to your peers for guidance on these issues. Any AAA studio will have at least one or two people who are more than qualified to advise you in person at a much greater level of detail.
Finally, while some parts of the STL and C++ standard library do have suboptimal performance for some common use cases (e.g. std::list, iostreams), other parts are generally pretty good (std::vector, std::copy). There's no rule that applies to the entire language...and if there were we'd probably be using another language!
That is up to the studio. You can write allocators to improve the memory performance based on the topology of your problem, you can create your traits with the exact same reason.
STL is an amazing tool, the problem with its usage is a lot programmers don't know how to, and end up using their own classes for basic things.
e.g, my actual company has a bunch of libraries written in c++ to avoid the STL, after more than 12 years, I found basic bugs in the string implementation, and one co-worker found another in the map.
STL can be blazing fast always you know how to. You should take a look at intel TBB + custom allocators + stl performance. Take a small look at this question Compelling examples of custom C++ allocators?

What is so great about STL? [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 9 years ago.
I am a Java developer trying to learn C++. I have many times read on the internet (including Stack Overflow) that STL is the best collections library that you can get in any language. (Sorry, I do not have any citations for that)
However after studying some STL, I am really failing to see what makes STL so special. Would you please shed some light on what sets STL apart from the collection libraries of other languages and make it the best collection library?
What is so great about the STL ?
The STL is great in that it was conceived very early and yet succeeded in using C++ generic programming paradigm quite efficiently.
It separated efficiently the data structures: vector, map, ... and the algorithms to operate on them copy, transform, ... taking advantage of templates to do so.
It neatly decoupled concerns and provided generic containers with hooks of customization (Comparator and Allocator template parameters).
The result is very elegant (DRY principle) and very efficient thanks to compiler optimizations so that hand-generated algorithms for a given container are unlikely to do better.
It also means that it is easily extensible: you can create your own container with the interface you wish, as long as it exposes STL-compliant iterators you'll be able to use the STL algorithms with it!
And thanks to the use of traits, you can even apply the algorithms on C-array through plain pointers! Talk about backward compatibility!
However, it could (perhaps) have been better...
What is not so great about the STL ?
It really pisses me off that one always have to use the iterators, I'd really stand for being able to write: std::foreach(myVector, [](int x) { return x+1;}); because face it, most of the times you want to iterate over the whole of the container...
But what's worse is that because of that:
set<int> mySet = /**/;
set<int>::const_iterator it = std::find(mySet.begin(), mySet.end(), 1005); // [1]
set<int>::const_iterator it = mySet.find(1005); // [2]
[1] and [2] are carried out completely differently, resulting in [1] having O(n) complexity while [2] has O(log n) complexity! Here the problem is that the iterators abstract too much.
I don't mean that iterators are not worthy, I just mean that providing an interface exclusively in terms of iterators was a poor choice.
I much prefer myself the idea of views over containers, for example check out what has been done with Boost.MPL. With a view you manipulate your container with a (lazy) layer of transformation. It makes for very efficient structures that allows you to filter out some elements, transform others etc...
Combining views and concept checking ideas would, I think, produce a much better interface for STL algorithms (and solve this find, lower_bound, upper_bound, equal_range issue).
It would also avoid common mistakes of using ill-defined ranges of iterators and the undefined behavior that result of it...
It's not so much that it's "great" or "the best collections library that you can get in *any* language", but it does have a different philosophy to many other languages.
In particular, the standard C++ library uses a generic programming paradigm, rather than an object-oriented paradigm that is common in languages like Java and C#. That is, you have a "generic" definition of what an iterator should be, and then you can implement the function for_each or sort or max_element that takes any class that implements the iterator pattern, without actually having to inherit from some base "Iterator" interface or whatever.
What I love about the STL is how robust it is. It is easy to extend it. Some complain that it's small, missing many common algorithms or iterators. But this is precisely when you see how easy it is to add in the missing components you need. Not only that, but small is beautiful: you have about 60 algorithms, a handful of containers and a handful of iterators; but the functionality is in the order of the product of these. The interfaces of the containers remain small and simple.
Because it's fashion to write small, simple, modular algorithms it gets easier to spot bugs and holes in your components. Yet, at the same time, as simple as the algorithms and iterators are, they're extraordinarily robust: your algorithms will work with many existing and yet-to-be-written iterators and your iterators work with many existing and yet-to-be-written algorithms.
I also love how simple the STL is. You have containers, you have iterators and you have algorithms. That's it (I'm lying here, but this is what it takes to get comfortable with the library). You can mix different algorithms with different iterators with different containers. True, some of these have constraints that forbid them from working with others, but in general there's a lot to play with.
Niklaus Wirth said that a program is algorithms plus data-structures. That's exactly what the STL is about. If Ruby and Python are string superheros, then C++ and the STL are an algorithms-and-containers superhero.
STL's containers are nice, but they're not much different than you'll find in other programming languages. What makes the STL containers useful is that they mesh beautifully with algorithms. The flexibility provided by the standard algorithms is unmatched in other programming languages.
Without the algorithms, the containers are just that. Containers. Nothing special in particular.
Now if you're talking about container libraries for C++ only, it is unlikely you will find libraries as well used and tested as those provided by STL if nothing else because they are standard.
The STL works beautifully with built-in types. A std::array<int, 5> is exactly that -- an array of 5 ints, which consumes 20 bytes on a 32 bit platform.
java.util.Arrays.asList(1, 2, 3, 4, 5), on the other hand, returns a reference to an object containing a reference to an array containing references to Integer objects containing ints. Yes, that's 3 levels of indirection, and I don't dare predict how many bytes that consumes ;)
This is not a direct answer, but as you're coming from Java I'd like to point this out. By comparison to Java equivalents, STL is really fast.
I did find this page, showing some performance comparisons. Generally Java people are very touchy when it comes to performance conversations, and will claim that all kinds of advances are occurring all the time. However similar advances are also occurring in C/C++ compilers.
Keep in mind that STL is actually quite old now, so other, newer libraries may have specific advantages. Given the age, its' popularity is a testament to how good the original design was.
There are four main reasons why I'd say that STL is (still) awesome:
Speed
STL uses C++ templates, which means that the compiler generates code that is specifically tailored to your use of the library. For example, map will automagically generate a new class to implement a map collection of 'key' type to 'value' type. There is no runtime overhead where the library tries to work out how to efficiently store 'key' and 'value' - this is done at compile time. Due to the elegant design some operations on some types will compile down to single assembly instructions (e.g. increment integer-based iterator).
Efficiency
The collections classes have a notion of 'allocators', which you can either provide yourself or use the library-provided ones which allocate only enough storage to store your data. There is no padding nor wastage. Where a built-in type can be stored more efficiently, there are specializations to handle these cases optimally, e.g. vector of bool is handled as a bitfield.
Exensibility
You can use the Containers (collection classes), Algorithms and Functions provided in the STL on any type that is suitable. If your type can be compared, you can put it into a container. If it goes into a container, it can be sorted, searched, compared. If you provide a function like 'bool Predicate(MyType)', it can be filtered, etc.
Elegance
Other libraries/frameworks have to implement the Sort()/Find()/Reverse() methods on each type of collection. STL implements these as separate algorithms that take iterators of whatever collection you are using and operate blindly on that collection. The algorithms don't care whether you're using a Vector, List, Deque, Stack, Bag, Map - they just work.
Well, that is somewhat of a bold claim... perhaps in C++0x when it finally gets a hash map (in the form of std::unordered_map), it can make that claim, but in its current state, well, I don't buy that.
I can tell you, though, some cool things about it, namely that it uses templates rather than inheritance to achieve its level of flexibility and generality. This has both advantages and disadvantages; a disadvantage is that lots of code gets duplicated by the compiler, and any sort of dynamic runtime typing is very hard to achieve; however, a key advantage is that it is incredibly quick. Because each template specialization is really its own separate class generated by the compiler, it can be highly optimized for that class. Additionally, many of the STL algorithms that operate on STL containers have general definitions, but have specializations for special cases that result in incredibly good performance.
STL gives you the pieces.
Languages and their environments are built from smaller component pieces, sometimes via programming language constructs, sometimes via cut-and-paste. Some languages give you a sealed box - Java's collections, for instance. You can do what they allow, but woe betide you if you want to do something exotic with them.
The STL gives you the pieces that the designers used to build its more advanced functionality. Directly exposing the iterators, algorithms, etc. give you an abstract but highly flexible way of recombining core data structures and manipulations in whatever way is suitable for solving your problem. While Java's design probably hits the 90-95% mark for what you need from data structures, the STL's flexibility raises it to maybe 99%, with the iterator abstraction meaning you're not completely on your own for the remaining 1%.
When you combine that with its speed and other extensibility and customizabiltiy features (allocators, traits, etc.), you have a quite excellent package. I don't know that I'd call it the best data structures package, but certainly a very good one.
Warning: percentages totally made up.
Unique because it
focuses on basic algorithms instead of providing ready-to-use solutions to specific application problems.
uses unique C++ features to implement those algorithms.
As for being best... There is a reason why the same approach wasn't (and probably won't) ever followed by any other language, including direct descendants like D.
The standard C++ library's approach to collections via iterators has come in for some constructive criticism recently. Andrei Alexandrescu, a notable C++ expert, has recently begun working on a new version of a language called D, and describes his experiences designing collections support for it in this article.
Personally I find it frustrating that this kind of excellent work is being put into yet another programming language that overlaps hugely with existing languages, and I've told him so! :) I'd like someone of his expertise to turn their hand to producing a collections library for the so-called "modern languages" that are already in widespread use, Java and C#, that has all the capabilities he thinks are required to be world-class: the notion of a forward-iterable range is already ubiquitous, but what about reverse iteration exposed in an efficient way? What about mutable collections? What about integrating all this smoothly with Linq? etc.
Anyway, the point is: don't believe anyone who tells you that the standard C++ way is the holy grail, the best it could possibly be. It's just one way among many, and has at least one obvious drawback: the fact that in all the standard algorithms, a collection is specified by two separate iterators (begin and end) and hence is clumsy to compose operations on.
Obviously C++, C#, and Java can enter as many pissing contests as you want them to. The clue as to why the STL is at least somewhat great is that Java was initially designed and implemented without type-safe containers. Then Sun decided/realised people actually need them in a typed language, and added generics in 1.5.
You can compare the pros and cons of each, but as to which of the three languages has the "greatest" implementation of generic containers - that is solely a pissing contest. Greatest for what? In whose opinion? Each of them has the best libraries that the creators managed to come up with, subject to other constraints imposed by the languages. C++'s idea of generics doesn't work in Java, and type erasure would be sub-standard in typical C++ usage.
The primary thing is, you can use templates to make using containers switch-in/switch-out, without having to resort to the horrendous mess that is Java's interfaces.
If you fail to see what usage the STL has, I recommend buying a book, "The C++ Programming Language" by Bjarne Stroustrup. It pretty much explains everything there is about C++ because he's the dude who created it.

STL or Qt containers?

What are the pros and cons of using Qt containers (QMap, QVector, etc.) over their STL equivalent?
I can see one reason to prefer Qt:
Qt containers can be passed along to other parts of Qt. For example, they can be used to populate a QVariant and then a QSettings (with some limitation though, only QList and QMap/QHash whose keys are strings are accepted).
Is there any other?
Edit: Assuming the application already relies on Qt.
This is a difficult to answer question. It can really boil down to a philosophical/subjective argument.
That being said...
I recommend the rule "When in Rome... Do as the Romans Do"
Which means if you are in Qt land, code as the Qt'ians do. This is not just for readability/consistency concerns. Consider what happens if you store everything in a stl container then you have to pass all that data over to a Qt function. Do you really want to manage a bunch of code that copies things into/out-of Qt containers. Your code is already heavily dependent on Qt, so its not like you're making it any more "standard" by using stl containers. And whats the point of a container if everytime you want to use it for anything useful, you have to copy it out into the corresponding Qt container?
I started by using std::(w)string and the STL containers exclusively and converting to/from the Qt equivalents, but I have already switched to QString and I find that I'm using Qt's containers more and more.
When it comes to strings, QString offers much more complete functionality compared to std::basic_string and it is
completely Unicode aware. It also offers an efficient COW implementation, which I've come to rely on heavily.
Qt's containers:
offer the same COW implementation as in QString, which is extremely useful when it comes to using Qt's foreach macro
(which does a copy) and when using meta-types or signals and slots.
can use STL-style iterators or Java-style iterators
are streamable with QDataStream
are used extensively in Qt's API
have a stable implementation across operating systems. A STL implementation must obey the C++ standard, but
is otherwise free to do as it pleases (see the std::string COW controversy). Some STL implementations are especially
bad.
provide hashes, which are not available unless you use TR1
The QTL has a different philosophy from the STL, which is well summarized by J. Blanchette: "Whereas STL's containers are optimized for raw speed, Qt's container classes have been carefully designed to provide convenience, minimal memory usage, and minimal code expansion."
The above link provides more details about the implementation of the QTL and what optimizations are used.
The Qt containers are more limited than the STL ones. A few examples of where the STL ones are superior (all of these I have hit in the past):
STL is standardized, doesn't change with every Qt version (Qt 2 had QList (pointer-based) and QValueList (value-based); Qt 3 had QPtrList and QValueList; Qt 4 now has QList, and it's nothing at all like QPtrList or QValueList). Qt 6 will have a QList that's QVector while QVector will be deprecated.
Even if you end up using the Qt containers, use the STL-compatible API subset (ie. push_back(), not append(); front(), not first(), ...) to avoid porting yet again come Qt 6. In both Qt2->3 and Qt3->4 transitions, the changes in the Qt containers were among those requiring the most code churn. I expect the same for Qt5->6.
STL bidirectional containers all have rbegin()/rend(), making reverse iteration symmetric to forward iteration. Not all Qt containers have them (the associative ones don't), so reverse iteration is needlessly complicated.
STL containers have range-insert() from different, but compatible, iterator types, making std::copy() much less often needed.
STL containers have an Allocator template argument, making custom memory management trivial (typedef required), compared with Qt (fork of QLineEdit required for s/QString/secqstring/). EDIT 20171220: This cuts Qt off of advances in allocator design following C++11 and C++17, cf. e.g. John Lakos' talk (part 2).
There's no Qt equivalent to std::deque.
std::list has splice(). Whenever I find myself using std::list, it's because I need splice().
std::stack, std::queue properly aggregate their underlying container, and don't inherit it, as QStack, QQueue do.
QSet is like std::unordered_set, not like std::set.
QList is a just weird.
Many of the above could be solved quite easily in Qt, but the container library in Qt seems to experience a lack of development focus at the moment.
EDIT 20150106: After having spent some time trying to bring C++11-support to Qt 5 container classes, I have decided that it's not worth the work. If you look at the work that is being put into C++ standard library implementations, it's quite clear that the Qt classes will never catch up. We've released Qt 5.4 now and QVector still doesn't move elements on reallocations, doesn't have emplace_back() or rvalue-push_back()... We also recently rejected a QOptional class template, waiting for std::optional instead. Likewise for std::unique_ptr. I hope that trend continues.
EDIT 20201009: Come Qt 6, they will again rewrite their containers in incompatible ways:
QVector will be renamed QList, so you lose stabiliy-of-reference when using QList.
QVector (the name) will be deprecated. QLinkedList will be removed.
QHash and QSet are now Open-Addressing Hash Tables, also losing stability-of-reference guarantees
QMap will be backed by std::map, possibly changing insertion behaviour and, for QMultiMap, order of equivalent elements.
Qt container sizes and indexes will become qsizetype (more or less std::ptrdiff_t) (was: int).
So, if you want to rewrite your container-using code, then go ahead with the Qt containers. Everyone else enjoys decades of stability with the STL containers.
Let's break down these claims into actual measurable phenomena:
Lighter: Qt containers use less memory than STL containers
Safer: Qt containers have less opportunity to be improperly used
Easier: Qt containers present less of an intellectual burden
Easier
The claim made in this context is that java-style iteration is somehow "easier" than STL style, and therefore Qt is easier to use because of this additional interface.
Java Style:
QListIterator<QString> i(list);
while (i.hasNext())
qDebug() << i.next();
STL Style:
QList<QString>::iterator i;
for (i = list.begin(); i != list.end(); ++i)
qDebug << *i;
The Java iterator style has the benefit of being a little smaller and cleaner.
The problem is, this isn't actually STL style anymore.
C++11 STL Style
for( auto i = list.begin(); i != list.end(); ++i)
qDebug << *i;
or
C++11 foreach style
for (QString i : list)
qDebug << i;
Which is so drastically simple that there's no reason to ever use anything else (unless you don't support C++11).
My favorite, however, is:
BOOST_FOREACH(QString i, list)
{
qDebug << i;
}
So, as we can see, this interface gains us nothing except an additional interface, on top of an already sleek, streamlined, and modern interface. Adding an unnecessary level of abstraction on top of an already stable and usable interface? Not my idea of "easier".
Also, Qt foreach and java interfaces add overhead; they copy the structure, and provide an unnecessary level of indirection. This might not seem like much, but why add a layer of overhead to provide a not-that-much-simpler interface? Java has this interface because java doesn't have operator overloading; C++ does.
Safer
The justification that Qt gives is the implicit sharing problem, which is neither implicit nor a problem. It does involve sharing, however.
QVector<int> a, b;
a.resize(100000); // make a big vector filled with 0.
QVector<int>::iterator i = a.begin();
// WRONG way of using the iterator i:
b = a;
/*
Now we should be careful with iterator i since it will point to shared data
If we do *i = 4 then we would change the shared instance (both vectors)
The behavior differs from STL containers. Avoid doing such things in Qt.
*/
First, this isn't implicit; you are explicitly assigning one vector to another. The STL iterator specification clearly indicates that iterators belong to the container, so we've clearly introduced a shared container between b and a. Second, this isn't a problem; as long as all the rules of the iterator specification are followed, absolutely nothing will go wrong. The only time something goes wrong is here:
b.clear(); // Now the iterator i is completely invalid.
Qt specifies this as if it means something, like a problem arises de novo from this scenario. It doesn't. The iterator is invalidated, and just like anything that can be accessed from multiple disjoint areas, this is just how it works. In fact, this will occur readily with Java style iterators in Qt, thanks to it's heavily reliance on implicit sharing, which is an antipattern as documented here, and at many other areas. It seems especially strange for this "optimization" to be put into use in a framework moving more and more towards multithreading, but that's marketing for you.
Lighter
This one is a bit trickier. The use of Copy-On-Write and Implicit Sharing and Growth Strategies makes it very difficult to actually make guarantees about how much memory your container will use at any given time. This is unlike the STL, which gives you strong algorithmic guarantees.
We know the minimal bound of wasted space for a vector is the square root of the length of the vector, but there seems to be no way to implement this in Qt; the various "optimizations" they support would preclude this very important space saving feature. The STL does not require this feature (and most use a doubling growth, which is more wasteful), but it's important to note that you could at least implement this feature, if need be.
The same is true of doubly linked lists, which could use XOr linking to drastically reduce space used. Again, this is impossible with Qt, due to it's requirements for growth and COW.
COW can indeed make something lighter, but so can Intrusive Containers, such as supported by boost, and Qt used these frequently in the earlier versions, but they are not used as much anymore because they are hard to use, unsafe, and impose a burden on the programmer. COW is a much less intrusive solution, but unattractive for the reasons posed above.
There is no reason why you could not use STL containers with the same memory cost or less than Qt's containers, with the added benefit of actually knowing how much memory you will waste at any given time. It is, unfortunately, impossible to compare the two in raw memory usage, because such benchmarks would show wildly different results in different use cases, which is the exact sort of problem that the STL was designed to correct.
In Conclusion
Avoid use of Qt Containers when ever possible to do so without imposing a copying cost, and use STL type iteration (perhaps through a wrapper or the new syntax), whenever possible.
STL containers:
Have performance guarantees
Can be used in STL algorithms which also have performance guarantees
Can be leveraged by third-party C++ libraries like Boost
Are standard, and likely to outlive proprietary solutions
Encourage generic programming of algorithms and data structures. If you write new algorithms and data structures that conform to STL you can leverage what STL already provides at no cost.
Qt containers use copy-on-write idiom.
One of the main issues is that Qt's API expects you to provide data in Qt's containers, so you may as well simply use the Qt containers rather than transforming back and forth between the two.
Also, if you're already using the Qt containers, it might be slightly more optimal to use them exclusively, as you would not have to include the STL header files and potentially link in the STL libraries. However, depending on your toolchain, that may happen anyway. Purely from a design perspective, consistency is generally a good thing.
If the data you are working with is mostly used to drive the Qt based UI, then definitely use Qt containers.
If the data is mostly used internally in the app, and you're never likely to port away from Qt, then barring performance issues, use the Qt containers because it will make the bits of data that go to the UI easier to deal with.
If the data is mostly used in conjunction with other libraries that only know about STL containers, then use STL containers. If you have this situation you're in trouble no matter what because you're going to do a lot of porting back and forth between container types no matter what you do.
Besides the COW difference, STL containers are much more widely supported on a variety of platforms. Qt is portable enough if you limit your work to "mainstream" platforms, but the STL is available on many other more obscure platforms too (e.g., Texas Instruments' DSPs).
Because the STL is standard rather than controlled by a single corporation, there are, generally speaking, more programmers who can easily read, understand, and modify STL code and more resources (books, online forums, conferences, etc.) to support them in doing this than there are for Qt. That's not to say that one should shy away from Qt for this reason alone; just that, all other things being equal, you should default to the STL, but of course all things are rarely equal, so you'll have to decide in your own context which makes the most sense.
In regard to AlexKR's answer: the STL performance is guaranteed within limits, but a given implementation may make use of platform-dependent details to speed up their STL. So in that sense, you may get different results on different platforms, but it will never be slower than the explicit guarantee (modulo bugs).
My five cents:
Qt containers are supposed to work similar on different platforms.
While STL containers depend on STL implementation.
You might get different performance results.
EDIT:
I am not telling that STL is "slower" but I point to effects of
various implementation details.
Please check this, and then maybe this.
And it is not a real problem of STL. Obviosly, if you have significant difference in performance, then there is problem in the code which uses STL.
I am of the opinion that STL is a excellent piece of software however if I am to do some KDE or Qt related programming then Qt is the way to go. Also it depends on the compiler you are using, with GCC STL works pretty good however if you have to use say SUN Studio CC then STL will most likely bring you headaches because of the compiler not the STL per se. In that case since the compiler will make your head hurt just use Qt to save you the trouble. Just my 2 cents...
There is a (sometimes) big limitation in QVector. It can only allocate int bytes of memory (note that the limit is in bytes not in number of elements). This implies that trying to allocate contiguous blocks of memory bigger than ~2GB with a QVector will lead to a crash. This happens with Qt 4 and 5. std::vector does not have such limitation.
I guess it depends on the way you use Qt. If you use it all over your product, than it probably makes sense to use Qt containers. If you contain it only to (for instance) the UI portion, it may be better to use C++ standard containers.
The main reason to go with STL containers for me is if you need a custom allocator in order to reuse memory in very big containers. Suppose for example that you have a QMap that stores 1000000 entries (key/value pairs). In Qt that implies exactly 1000000 million allocations (new calls) no matter what. In STL you can always create a custom allocator that internally allocates all that memory at once and assign it to each entry as the map is populated.
My advice is to use STL containers when writing performance critical algorithms in the business logic and then convert them back to Qt containers when the results are ready to by displayed by your UI controls and forms if needed.

Programmer productivity with STL vs. custom utility classes

I work in an environment where, for historical reasons, we are using a hodgepodge of custom utility classes, most of which were written before STL arrived on the scene. There are many reasons why I think it is a good idea to at least write new code using STL, but the main one is that I believe it increases programmer productivity. Unfortunately, that is a point that I don't know how to prove.
Are there any studies out there that attempt to quantify, or even just hint at, a productivity gain from using STL?
Update: I guess I should have been more specific. I am not advocating rewriting existing code, and I am not worried about the new hires that will get a running start. The former would be foolish, and the latter by itself is not enough to convince people.
There are no studies that will show STL is more productive just because it is STL. Productivity gains from using it are due to it being a standard programmers are familiar with it, and because the code is already written and tested.
If your company already has utility classes that employees are familiar with, and this utility code is used throughout an existing codebase, then switching to STL could actually be detrimental to productivity.
That said for new code using STL would be a good move. I would not necessarily argue this from a productivity standpoint, but one of maintainability. If you have code that predates STL it sounds like code at your company has quite a long lifetime and is likely to be maintained by a number of new programmers over the years.
You may also want to broach the use of STL as a way for everyone to keep their C++ skillset sharp. While I wouldn't reject a C++ candidate who didn't know STL, I would definitely view it as a black mark.
The reason the STL is so "good" is simply because it's been around a long time now and the implementations have seen a lot of users and eyes. They're well debugged and the algorithms have been pretty well optimized by vendors.
STL will be more productive for new devs in your shop because it's likely they are already familiar with it. Your custom libs will be foreign and probably lacking in features that devs are accustomed to using. That's not a huge issue after the initial ramp-up period for new devs though.
There's no real pressing reason to shift to STL just because it is. If you have perfectly useful utility classes in your application I'd recommend sticking with them unless they're not workable for new code. Mixing STL with your custom libraries in new code is going to cause compatibility problems at some point and refactoring the code to use all STL is going to introduce bugs. Either way you'll be losing productivity.
Edit: By "new" code, I mean new code in existing applications using the older class libraries.
If you're developing new standalone apps that do not draw on any of the old applicaiton code I'd recommend STL because it's there, most every C++ dev knows how to use it and it's pretty stable (and you get support from your toolset vendor if it's not).
The only argument for increasing productivity with STL I can think of would be a possibility of integrating other libraries easily - Boost, Arabica, SOCI, etc. They are all designed to work with STL, not your in-house container classes.
I think the critical factor is the turnover rate of the development team.
If the team is stable, and they've been working on this code for ten years and probably will be ten years from now, they will be more productive using the utility classes they're familiar with, and nudging them to use the STL will result in reduced productivity and bugs.
If the team turns over a lot, then the new developers will likely be familiar with the STL, and obviously not this proprietary utility class library, and will do better with the STL.
I have been in the same situation. It depends on the utility classes in question. Many custom utility classes I have seen have been buggy, or poorly designed, and are causing bugs and inefficiencies throughout the source. In this case, a straight replacement with STL equivalents will improve the codebase, increase productivity, decrease bugs and reduce maintainance costs for the future.
You can sometimes help to bridge the gap between the two worlds by retrofitting STL-style iterators to your old classes, though be careful to get them right!
It may be that the reverse is true where the home-grown utilities are in any way domain-specific to the work you do.
One place where STL is useful is not in the actual libraries etc that are provide by STL but rather in the coding style that STL uses.
In the following there are 2 main tests required:
struct DoSomething {
bool operator ()(Container::value_type const & v) const
{
// ...
}
};
void bar (Container const & c)
{
std::for_each (c.begin (), c.end (), DoSomething ());
}
The first tests verify that 'DoSomething::operator()' does what it's supposed to do. The second test only needs to verify that 'DoSomething::operator()' is called.
This separation can help improve productivity when compared with a hand written for loop. For the above, the number of tests is the sum of the "thing to be done" and the tests that the call is made for a non empty container. In the case of the for loop the number of tests is the product of the tests.
The reasons I see are:
Quality of the code
The writers of the STL (either its interface, or the implementation for your compilers) are without doubts magnitudes better than the best developer in your company.
Their job is to make a usable STL, which means that every function/method/object is heavily tested anyway.
Maintainability of the code
With the turnover, some code can become slowly and stealthily unmaintained. Which means that if there is a bug in this code, or if its performance or interface are found lacking (see the "Quality" above), then you'll find no one to expertly improve it.
The code change will have a non-zero probability of a code regression elsewhere, and if your in-house library is not unit-tested, that this regression will go undetected for quite some time.
And I'm not even mentioning the "I WON'T ever touch that slimy code" syndrome when someone trying to correct the code just finds he doesn't understand why it was done this way (because of macros, strange pre-conditions, etc..
Conclusion
Combine the two, and you'll find that for generic code (i.e. arrays, strings, etc.), you'll go better by slowly migrating from in-house libraries to STL library, writting "converter functions" when needed.
I think this kind of migration is part of the maintenance of your code, and that you should slowly (i.e. with new code, or when refactoring), whenever possible, use STL instead of in-house generic libraries.
Since you already have the utility classes, there's no need for using the STL. It will quickly become a maintainability problem as you find the need to begin integrating the STL into your utility libraries. IMO, it will be a productivity loss.
That said, the STL may offer a lot of features and utilities that your utility libraries don't provide. (Particularly useful is the <algorithms> header, which you can probably begin using immediately without many problems with legacy code.) If you're writing a lot of new code, it's far better to use the STL (and Boost, if you can) than to write your own utility classes and algorithms. As a result, it will be a major productivity gain.
I don't know of any studies on the topic, though.
Consider the situation when you hire a new C++ programmer. Is s/he more likely to have experience with STL classes or your own ones? You could be looking at huge savings in time before they become productive if you start to switch to the STL.
Currently, any newly hired employee will have to learn how to use the old classes, and that costs time and money. Using STL like everyone else would save your company money and keep it attractive among the pool of candidates.
I don't think there is a way to justify replacing these custom classes wholesale, unfortunately. If possible, replace them with STL components a class at at time.
This is a maintenance & readability issue as much as anything. (1) Using STL helps maintainers understand the code at a glance, versus needeing to learn their way around custom implementations. (2) The STL is WELL documented and well understood - what about your custom classes? (3) The STL is well vetted. (4) The STL comes with asymptotic runtime upper & lower bounds.
Good luck.

Good Idea / Bad Idea Should I Reimplement Most Of C++? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
Recently, I've got a dangerous idea into my head after reading this blog post. That idea can be expressed like this:
I don't need most of what the C++ standard library offers. So, why don't I implement a less general, but easier to use version?
As an example, using the STL spits out reams of incomprehensible and mangled compiler errors. But, I don't care about allocators, iterators and the like. So why don't I take a couple of hours and implement an easy to use linked list class, for example?
What I'd like to know from the StackOverflow community is this: what are the dangers, possible disadvantages and possible advantages to "rolling my own" for most of the existing functionality in C++?
Edit: I feel that people have misunderstood me about this idea. The idea was to understand whether I could implement a very small set of STL functionality that is greatly simplified - more as a project to teach me about data structures and the like. I don't propose re-inventing the entire wheel from the ground up, just the part that I need and want to learn about. I suppose what I wanted to figure out is whether the complexity of using the STL warrants the creation of smaller, simpler version of itself.
Re-using boost or similiar.
Most of what I code is for University and we're not allowed to use external libraries. So it's either the C++ standard library, or my own classes.
Objectivity of this question.
This question is not subjective. Nor should it be community Wiki, since it's not a poll. I want concrete arguments that highlight one advantage or one disadvantage that could possibly occur with my approach. Contrary to popular belief, this is not opinion, but based on experience or good logical arguments.
Format.
Please post only one disadvantage or one advantage per answer. This will allow people to evaluate individual ideas instead of all your ideas at once.
And please...
No religious wars. I'm not a fan boy of any language. I use whatever's applicable. For graphics and data compression (what I'm working on at the moment) that seems to be C++. Please constrain your answers to the question or they will be downvoted.
So, why don't I implement a less
general, but easier to use version?
Because you can't. Because whatever else you might say about C++, it is not a simple language, and if you're not already very good at it, your linked list implementation will be buggy.
Honestly, your choice is simple:
Learn C++, or don't use it. Yes, C++ is commonly used for graphics, but Java has OpenGL libraries too. So does C#, Python and virtually every other language. Or C. You don't have to use C++.
But if you do use it, learn it and use it properly.
If you want immutable strings, create your string as const.
And regardless of its underlying implementation, the STL is remarkably simple to use.
C++ compiler errors can be read, but it takes a bit of practice. But more importantly, they are not exclusive to STL code. You'll encounter them no matter what you do, and which libraries you use. So get used to them. And if you're getting used to them anyway, you might as well use STL too.
Apart from that, a few other disadvantages:
No one else will understand your code. If you ask a question on SO about std::vector, or bidirectional iterators, everyone who's reasonably familiar with c++ can answer. If you ask abut My::CustomLinkedList, no one can help you. Which is unfortunate, because rolling your own also means that there will be more bugs to ask for help about.
You're trying to cure the symptom, rather than the cause. The problem is that you don't understand C++. STL is just a symptom of that. Avoiding STL won't magically make your C++ code work better.
The compiler errors. Yes, they're nasty to read, but they're there. A lot of work in the STL has gone into ensuring that wrong use will trigger compiler errors in most cases. In C++ it's very easy to make code that compiles, but doesn't work. Or seems to work. Or works on my computer, but fails mysteriously elsewhere. Your own linked list would almost certainly move more errors to runtime, where they'd go undetected for a while, and be much harder to track down.
And once again, it will be buggy. Trust me. I've seen damn good C++ programmers write a linked list in C++ only to uncover bug after bug, in obscure border cases. And C++ is all border cases. Will your linked list handle exception safety correctly? Will it guarantee that everything is in a consistent state if creating a new node (and thereby calling the object type's constructor) throws an exception? That it won't leak memory, that all the appropriate destructors will be called? Will it be as type-safe? Will it be as performant? There are a lot of headaches to deal with when writing container classes in C++.
You're missing out on one of the most powerful and flexible libraries in existence, in any language. The STL can do a lot that would be a pain even with Java's giant bloated class library. C++ is hard enough already, no need to throw away the few advantages it offers.
I don't care about allocators,
iterators and the like
Allocators can be safely ignored. You pretty much don't even need to know that they exist. Iterators are brilliant though, and figuring them out would save you a lot of headaches. There are only three concepts you need to understand to use STL effectively:
Containers: You already know about these. vectors, linked lists, maps, sets, queues and so on.
Iterators: Abstractions that let you navigate a container (or subsets of a container, or any other sequence of value, in memory, on disk in the form of streams, or computed on the fly).
Algorithms: Common algorithms that work on any pair of iterators. You have sort, for_each, find, copy and many others.
Yes, the STL is small compared to Java's library, but it packs a surprising amount of power when you combine the above 3 concepts. There's a bit of a learning curve, because it is an unusual library. But if you're going to spend more than a day or two with C++, it's worth learning properly.
And no, I'm not following your answer format, because I thought actually giving you a detailed answer would be more helpful. ;)
Edit:
It'd be tempting to say that an advantage of rolling your own is that you'd learn more of the language, and maybe even why the STL is one of its saving graces.. But I'm not really convinced it's true. It might work, but it can backfire too.
As I said above, it's easy to write C++ code that seems to work. And when it stops working, it's easy to rearrange a few things, like the declaration order of variables, or insert a bit of padding in a class, to make it seemingly work again. What would you learn from that? Would that teach you how to write better C++? Perhaps. But most likely, it'd just teach you that "C++ sucks". Would it teach you how to use the STL? Definitely not.
A more useful approach might be utilizing the awesome power of StackOverflow in learning STL the right way. :)
Disadvantage: no one but you will use it.
Advantage: In the process of implementing it you will learn why the Standard Library is a good thing.
Advantages: eating your own dogfood. You get exactly what you do.
Disadvantages: eating your own dogfood. Numerous people, smarter than 99 % of us, have spent years creating STL.
I suggested you learn why:
using the STL spits out reams of
incomprehensible and mangled compiler
errors
first
Disadvantage: you may spend more time debugging your class library than solving whatever university task you have in front of you.
Advantage: you're likely to learn a lot!
There is something you can do about the cryptic compiler STL error messages. STLFilt will help simplify them. From the STLFilt Website:
STLFilt simplifies and/or reformats
long-winded C++ error and warning
messages, with a focus on STL-related
diagnostics (and for MSVC 6, it fully
eliminates C4786 warnings and their
detritus). The result renders many of
even the most cryptic diagnostics
comprehensible.
Have a look here and, if you are using VisualC, also here.
I think you should do it.
I'm sure I'll get flambayed for this, but you know, every C++ programmer around here has drunk a little too much STL coolaid.
The STL is a great library, but I know from first hand experience that if you roll your own, you can:
1) Make it faster than the STL for your particular use cases.
2) You'll write a library with just the interfaces you need.
3) You'll be able to extend all the standard stuff. (I can't tell you how much I've wished std::string had a split() method)...
Everyone is right when they say that it will be a lot of work. Thats true.
But, you will learn a lot. Even if after you write it, you go back to the STL and never use it again, you'll still have learned a lot.
A bit of my experience : Not that long ago I have implemented my own vector-like class because I needed good control on it.
As I needed genericity I made a templated array.
I also wanted to iterate through it not using operator[] but incrementing a pointer like a would do with C, so I don't compute the address of T[i] at each iteration... I added two methods one to return pointer to the allocated memory and another that returns a pointer to the end.
To iterate through an array of integer I had to write something like this :
for(int * p = array.pData(); p != array.pEnd(); ++p){
cout<<*p<<endl;
}
Then when I start to use vectors of vectors I figure out that when it was possible a could allocate a big bloc of memory instead of calling new many times. At this time I add an allocator to the template class.
Only then I notice that I had wrote a perfectly useless clone of std::vector<>.
At least now I know why I use STL...
Disadvantage : IMHO, reimplimenting tested and proven libraries is a rabit hole which is almost garanteed to be more trouble than it's worth.
Another Disadvantage:
If you want to get a C++ job when you're finished with University, most people who would want to recruit you will expect that you are familiar with the Standard C++ library. Not necessarily intimately familiar to the implementation level but certainly familiar with its usage and idioms. If you reimplement the wheel in form of your own library, you'll miss out on that chance. This is nonwithstanding the fact that you will hopefully learn a lot about library design if you roll your own, which might earn you a couple of extra brownie points depending on where you interview.
Disadvantage:
You're introducing a dependency on your own new library. Even if that's sufficient, and your implementation works fine, you still have a dependency. And that can bite you hard with code maintenance. Everyone else (including yourself, in a year's time, or even a month's) will not be familiar with your unique string behavior, special iterators, and so on. Much effort will be needed just to adapt to the new environment before you could ever start refactoring/extending anything.
If you use something like STL, everyone will know it already, it's well understood and documented, and nobody will have to re-learn your custom throwaway environment.
You may be interested in EASTL, a rewrite of the STL Electronic Arts documented a while back. Their design decisions were mostly driven by the specific desires/needs in multiplatform videogame programming. The abstract in the linked article sums it up nicely.
Advantage
If you look into MFC, you'll find that your suggestion already is used in productive code - and has been so for a long time. None of MFC's collection classes uses the STL.
Why don't you take a look at existing C++ libraries. Back when C++ wasn't quite as mature, people often wrote their own libraries. Have a look at Symbian (pretty horrible though), Qt and WxWidgets (if memory serves me) have basic collections and stuff, and there are probably many others.
My opinion is that the complexity of STL derives from the complexity of the C++ language, and there's little you can do to improve on STL (aside from using a more sensible naming convention). I recommend simply switching to some other language if you can, or just deal with it.
Disadvantage : You're university course is probably laid out like this for a reason. The fact that you are irritated enough by it (sarcasm not intended), may indicate you are not getting the paridigm, and will benefit a lot when you have a paradigm shift.
As an example, using the STL spits out
reams of incomprehensible and mangled
compiler errors
The reason for this is essentially C++ templates. If you use templates (as STL does) you will get reams of incomprehensible error messages. So if you implement your own template based collection classes you will not be in any better spot.
You could make non template based containers and store everything as void pointers or some base class e.g. But you would lose compile time type checks and C++ sucks as a dynamic language. It is not as safe to do this as it would be in e.g. Objective-C, Python or Java. One of the reasons being that C++ does not have a root class for all classes to all introspection on all objects and some basic error handling at runtime. Instead your app would likely crash and burn if you were wrong about the type and you would not be given any clues to what went wrong.
Disadvantage: reimplementing all of that well (that is, at a high level of quality) will certainly take a number of great developers a few years.
what are the dangers, possible disadvantages and possible advantages to "rolling my own" for most of the existing functionality in C++?
Can you afford and possibly justify the amount of effort/time/money spent behind reinventing the wheel?
Re-using boost or similiar.
Rather strange that you cannot use Boost. IIRC, chunks of contribution come in from people related to/working in universities (think Jakko Jarvi). The upsides of using Boost are far too many to list here.
On not 'reinventing the wheel'
Disadvantage: While you learn a lot, you also set yourself back, when you come to think of what your real project objectives are.
Advantage: Maintenance is easier for the folks who are going to inherit this.
STL is very complex because it needs to be for a general purpose library.
Reasons why STL is the way it is:
Based on interators so standard algorithms only need a single implementation for different types of containers.
Designed to behave properly in the face of Exceptions.
Designed to be 'thread' safe in multi threaded applications.
In a lot of applications however you really have enough with the following:
string class
hash table for O(1) lookups
vector/array with sort / and binary search for sorted collections
If you know that:
Your classes do not throw exceptions on construction or assignment.
Your code is single threaded.
You will not use the more complex STL algorithms.
Then you can probably write your own faster code that uses less memory and produces simpler compile/runtime errors.
Some examples for faster/easier without the STL:
Copy-on-Write string with reference counted string buffer. (Do not do this in a multi-threaded environment since you would need to lock on the reference count access.)
Use a good hash table instead of the std::set and std::map.
'Java' style iterators that can be passed around as a single object
Iterator type that does not need to know the type of the container (For better compile time decoupling of code)
A string class with more utility functions
Configurable bounds checking in your vector containers. (So not [] or .at but the same method with a compile or runtime flag for going from 'safe' to 'fast' mode)
Containers designed to work with pointers to objects that will delete their content.
It looks like you updated the question so now there are really two questions:
What should I do if I think the std:: library is too complex for my needs?
Design your own classes that internally use relevant std:: library features to do the "heavy lifting" for you. That way you have less to get wrong, and you still get to invent your own coding interface.
What should I do if I want to learn how data structures work?
Design your own set of data structure classes from the ground up. Then try to figure out why the standard ones are better.