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:
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.
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).
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:
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.QDataStream
std::string
COW controversy). Some STL implementations are especially
bad.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.
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.
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):
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.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.insert()
from different, but compatible, iterator types, making std::copy()
much less often needed.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).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 guaranteesQMap
will be backed by std::map
, possibly changing insertion behaviour and, for QMultiMap
, order of equivalent elements.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.
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.