C++ STL 还是 Qt 容器?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1668259/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
STL or Qt containers?
提问by Julien-L
What are the pros and cons of using Qt containers (QMap
, QVector
, etc.) over their STL equivalent?
什么是使用Qt容器(的利弊QMap
,QVector
在他们的STL等价物,等等)?
I can see one reason to prefer Qt:
我可以看到更喜欢 Qt 的一个原因:
- Qt containers can be passed along to other parts of Qt. For example, they can be used to populate a
QVariant
and then aQSettings
(with some limitation though, onlyQList
andQMap
/QHash
whose keys are strings are accepted).
- Qt 容器可以传递到 Qt 的其他部分。例如,它们可用于填充 a
QVariant
和 aQSettings
(尽管有一些限制,仅接受QList
和QMap
/QHash
其键是字符串)。
Is there any other?
还有其他的吗?
Edit: Assuming the application already relies on Qt.
编辑:假设应用程序已经依赖于 Qt。
采纳答案by rpg
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.
我开始只使用std::(w)string
STL 容器,并在 Qt 等效项之间进行转换,但我已经切换到QString
并且我发现我越来越多地使用 Qt 的容器。
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.
与字符串QString
相比std::basic_string
,它提供了更完整的功能,并且完全支持 Unicode。它还提供了一个高效的 COW 实现,我非常依赖它。
Qt's containers:
Qt 的容器:
- offer the same COW implementation as in
QString
, which is extremely useful when it comes to using Qt'sforeach
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
- 提供与 中相同的 COW 实现
QString
,这在使用 Qt 的foreach
宏(进行复制)以及使用元类型或信号和插槽时非常有用。 - 可以使用 STL 风格的迭代器或 Java 风格的迭代器
- 可以流式传输
QDataStream
- 在 Qt 的 API 中广泛使用
- 具有跨操作系统的稳定实现。STL 实现必须遵守 C++ 标准,但可以自由地为所欲为(参见
std::string
COW 争议)。一些 STL 实现尤其糟糕。 - 提供哈希,除非您使用 TR1,否则不可用
The QTL has a different philosophy from the STL, which is well summarizedby 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.
QTL 与 STL 有着不同的理念,J. Blanchette很好地总结了这一点:“虽然 STL 的容器针对原始速度进行了优化,但 Qt 的容器类经过精心设计,以提供便利、最少的内存使用和最少的代码扩展。”
上面的链接提供了有关 QTL 实现和使用哪些优化的更多详细信息。
回答by Doug T.
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?
这意味着如果您在 Qt 领域,请像 Qt'ians 一样进行编码。这不仅仅是为了可读性/一致性问题。考虑一下如果将所有内容存储在 stl 容器中会发生什么,那么您必须将所有数据传递给 Qt 函数。你真的想管理一堆将东西复制到 Qt 容器中/从 Qt 容器中复制出来的代码吗?您的代码已经严重依赖 Qt,所以它不像您通过使用 stl 容器使其更加“标准”。如果每次你想用它做任何有用的事情时,你都必须将它复制到相应的 Qt 容器中,那么容器有什么意义呢?
回答by Marc Mutz - mmutz
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):
Qt 容器比 STL 容器更受限制。一些 STL 优势的例子(所有这些我过去都遇到过):
- STL is standardized, doesn't change with every Qt version (Qt 2 had
QList
(pointer-based) andQValueList
(value-based); Qt 3 hadQPtrList
andQValueList
; Qt 4 now hasQList
, and it's nothing at all likeQPtrList
orQValueList
).
Even if you end up using the Qt containers, use the STL-compatible API subset (ie.push_back()
, notappend()
;front()
, notfirst()
, ...) to avoid porting yet again come Qt 5. In both Qt2->3 and Qt3->4 transitions, the changes in the Qt containers were among those requiring the most code churn. - 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, makingstd::copy()
much less often needed. - STL containers have an
Allocator
template argument, making custom memory management trivial(typedef required), compared with Qt(fork ofQLineEdit
required fors/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
hassplice()
. Whenever I find myself usingstd::list
, it's because I needsplice()
.std::stack
,std::queue
properly aggregate their underlying container, and don't inherit it, asQStack
,QQueue
do.QSet
is likestd::unordered_set
, not likestd::set
.QList
is a just weird.
- STL 是标准化的,不会随着每个 Qt 版本而改变(Qt 2 有
QList
(基于指针的)和QValueList
(基于值的);Qt 3 有QPtrList
和QValueList
;Qt 4 现在有QList
,它根本不像QPtrList
或QValueList
)。
即使您最终使用 Qt 容器,也请使用 STL 兼容的 API 子集(即push_back()
,不是append()
;front()
,不是first()
...)以避免再次移植 Qt 5。在 Qt2->3 和 Qt3->4 中转换,Qt 容器中的更改是需要最多代码搅动的更改之一。 - STL 双向容器都有
rbegin()
/rend()
,使得反向迭代与正向迭代对称。并非所有 Qt 容器都有它们(关联容器没有),因此反向迭代是不必要的复杂。 - STL 容器具有范围
insert()
不同但兼容的迭代器类型,因此std::copy()
很少需要。 - STL 容器有一个
Allocator
模板参数,与Qt(fork of required for )相比,自定义内存管理变得微不足道(需要 typedef )。编辑 20171220:这切断了 Qt 在 C++11 和 C++17 之后的分配器设计方面的进步,参见。例如John Lakos 的演讲(第 2 部分)。QLineEdit
s/QString/secqstring/
- 没有等效于
std::deque
. std::list
有splice()
. 每当我发现自己在使用 时std::list
,都是因为我需要splice()
.std::stack
,std::queue
正确汇集其基本容器,不继承它,因为QStack
,QQueue
这样做。QSet
是喜欢std::unordered_set
,不是喜欢std::set
。QList
是只是奇怪。
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.
以上许多问题在 Qt 中都可以很容易地解决,但是Qt 中的容器库目前似乎缺乏开发重点。
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
stilldoesn'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.
编辑 20150106:在花了一些时间尝试将 C++11 支持引入 Qt 5 容器类之后,我决定不值得这样做。如果您查看投入到 C++ 标准库实现中的工作,很明显 Qt 类永远不会赶上。我们现在已经发布了 Qt 5.4,QVector
但仍然不会在重新分配时移动元素,没有emplace_back()
或 rvalue-......push_back()
我们最近还拒绝了一个QOptional
类模板,std::optional
而是等待。同样对于std::unique_ptr
. 我希望这种趋势继续下去。
回答by Alice
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
- 更轻:Qt 容器比 STL 容器使用更少的内存
- 更安全:Qt 容器被不当使用的机会更少
- 更简单:Qt 容器带来的智力负担更小
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 样式的迭代在某种程度上比 STL 样式“更容易”,因此 Qt 更易于使用,因为这个附加接口。
Java Style:
爪哇风格:
QListIterator<QString> i(list);
while (i.hasNext())
qDebug() << i.next();
STL Style:
STL风格:
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.
Java 迭代器风格的好处是更小更干净。问题是,这实际上不再是 STL 风格了。
C++11 STL Style
C++11 STL 风格
for( auto i = list.begin(); i != list.end(); ++i)
qDebug << *i;
or
或者
C++11 foreach style
C++11 foreach 风格
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).
这非常简单,以至于没有理由使用其他任何东西(除非您不支持 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.
此外,Qt foreach 和 java 接口增加了开销;它们复制结构,并提供不必要的间接级别。这可能看起来不多,但为什么要增加一层开销来提供一个不那么简单的界面呢?Java有这个接口是因为java没有操作符重载;C++ 可以。
Safer
更安全
The justification that Qt gives is the implicit sharing problem, which is neither implicit nor a problem. It does involve sharing, however.
Qt 给出的理由是隐式共享问题,这既不是隐式也不是问题。然而,它确实涉及共享。
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:
首先,这不是隐含的;您明确地将一个向量分配给另一个向量。STL 迭代器规范明确指出迭代器属于容器,因此我们明确地在 b 和 a 之间引入了一个共享容器。其次,这不是问题;只要遵循迭代器规范的所有规则,绝对不会出错。唯一出错的时候是在这里:
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.
Qt 将此指定为好像它意味着什么,就像这个场景从头出现问题一样。它没有。迭代器失效,就像可以从多个不相交区域访问的任何东西一样,这就是它的工作原理。事实上,这很容易在 Qt 中使用 Java 风格的迭代器发生,这要归功于它严重依赖隐式共享,这是这里和许多其他领域中记录的反模式。在一个越来越多线程的框架中使用这种“优化”似乎特别奇怪,但这对你来说是营销。
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.
这个有点棘手。Copy-On-Write 和隐式共享和增长策略的使用使得实际上很难保证您的容器在任何给定时间将使用多少内存。这与 STL 不同,后者为您提供强大的算法保证。
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.
我们知道向量浪费空间的最小界限是向量长度的平方根,但似乎没有办法在 Qt 中实现这一点;他们支持的各种“优化”将排除这个非常重要的空间节省功能。STL 不需要此功能(并且大多数使用双倍增长,这更浪费),但重要的是要注意,如果需要,您至少可以实现此功能。
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.
双向链表也是如此,它可以使用异或链接来大大减少使用的空间。同样,这对于 Qt 来说是不可能的,因为它需要增长和 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.
COW 确实可以做一些更轻的东西,但是 Intrusive Containers 也可以,比如boost支持,Qt 在早期版本中经常使用这些,但它们不再使用了,因为它们难以使用,不安全,并且带来负担在程序员上。COW 是一种侵入性小得多的解决方案,但由于上述原因,它没有吸引力。
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.
没有理由不使用具有与 Qt 容器相同或更少内存成本的 STL 容器,另外的好处是实际知道在任何给定时间会浪费多少内存。不幸的是,无法在原始内存使用情况上比较两者,因为这样的基准测试会在不同的用例中显示出截然不同的结果,而这正是 STL 旨在纠正的那种问题。
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.
在不增加复制成本的情况下尽可能避免使用 Qt 容器,并尽可能使用 STL 类型迭代(可能通过包装器或新语法)。
回答by fbrereto
STL containers:
STL容器:
- 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.
- 有性能保证
- 可用于也有性能保证的STL 算法
- 可以被 Boost 等第三方 C++ 库利用
- 是标准的,并且可能比专有解决方案寿命更长
- 鼓励算法和数据结构的通用编程。如果您编写符合 STL 的新算法和数据结构,您可以免费利用 STL 已经提供的功能。
回答by TimW
Qt containers use copy-on-write idiom.
Qt 容器使用写时复制习语。
回答by qid
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.
主要问题之一是 Qt 的 API 期望您在 Qt 的容器中提供数据,因此您不妨简单地使用 Qt 容器,而不是在两者之间来回转换。
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.
此外,如果您已经在使用 Qt 容器,那么单独使用它们可能会稍微优化一些,因为您不必包含 STL 头文件和 STL 库中的潜在链接。但是,根据您的工具链,无论如何都可能发生这种情况。纯粹从设计的角度来看,一致性通常是一件好事。
回答by Michael Kohne
If the data you are working with is mostly used to drive the Qt based UI, then definitely use Qt containers.
如果您使用的数据主要用于驱动基于 Qt 的 UI,那么一定要使用 Qt 容器。
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.
如果数据主要在应用程序内部使用,并且您永远不可能从 Qt 移植,那么除非性能问题,请使用 Qt 容器,因为它会使进入 UI 的数据位更容易处理。
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.
如果数据主要是与其他只了解STL容器的库结合使用,那么使用STL容器。如果您遇到这种情况,无论如何您都会遇到麻烦,因为无论您做什么,您都将在容器类型之间来回进行大量移植。
回答by metal
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).
除了 COW 的不同之外,STL 容器在各种平台上得到了更广泛的支持。如果您将工作限制在“主流”平台上,Qt 是足够便携的,但是 STL 也可以在许多其他更模糊的平台上使用(例如,德州仪器的 DSP)。
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.
由于 STL 是标准的,而不是由单个公司控制,因此一般来说,有更多的程序员可以轻松阅读、理解和修改 STL 代码以及更多资源(书籍、在线论坛、会议等)来支持他们这样做比 Qt 有。这并不是说仅仅因为这个原因就应该回避 Qt;只是,在所有其他条件相同的情况下,您应该默认使用 STL,但当然所有事情很少是相同的,因此您必须根据自己的上下文来决定哪个最有意义。
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 uptheir 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).
关于 AlexKR 的回答:STL 性能在限制范围内得到保证,但给定的实现可能会利用平台相关的细节来加速其 STL。所以从这个意义上说,你可能会在不同的平台上得到不同的结果,但它永远不会比显式保证(模错误)慢。
回答by alexkr
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.
我的五分钱:Qt 容器应该在不同的平台上以类似的方式工作。而 STL 容器依赖于 STL 实现。您可能会得到不同的性能结果。
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.
编辑:我不是在说 STL“较慢”,但我指出了各种实现细节的影响。
请检查这个,然后也许这个。
这不是 STL 的真正问题。显然,如果性能有显着差异,那么使用 STL 的代码就有问题。