Qt 容器架构与应用深度解析
1. 引言:Qt 容器的理论基础与设计哲学
本节旨在为 Qt 容器库的存在建立基础背景。它将超越简单的 API 介绍,深入探讨塑造其发展的战略性工程决策,为后续的详细技术分析奠定基础。
1.1. 历史背景:一个前标准化的世界
Qt 的开发始于一个 C++ 标准库(特别是 STL)尚未在所有支持的平台上普及或实现一致的时代 1。早期的 Qt 版本必须提供自己的基础数据结构,以保证跨平台功能的正常工作 3。这种历史必然性是 Qt 容器库存在的主要原因。这并非出于偏好而“重新发明轮子”,而是对 20 世纪 90 年代和 21 世纪初 C++ 领域碎片化现状的务实解决方案 2。这段历史对于理解 Qt 为何要开发一个平行的类生态系统至关重要。
在那个时期,不同编译器对 C++ 标准的支持程度参差不齐,STL 的可用性和性能也常常是开发者面临的难题。对于一个以跨平台为核心价值的框架而言,依赖于这样一个不确定的外部组件是不可接受的。因此,Qt 团队选择创建自己的容器类,以确保无论开发者在 Windows、Linux 还是其他嵌入式平台上编译,都能获得一致、可靠的行为。这套自有的容器库成为了 Qt 框架稳定性的基石之一。
1.2. 核心设计原则:更轻、更安全、更易用
Qt 的官方文档始终将其容器描述为“比 STL 容器更轻、更安全、更易用” 1。这一理念体现在多个方面,例如隐式共享(implicit sharing)技术、自动将原生类型初始化为零(例如int 和 double)6,以及提供一个更便捷、更符合“Qt 风格”的 API(例如,使用append() 而非 push_back())1。
这些原则反映了 Qt 在设计上对开发者生产力和代码稳健性的高度重视,有时甚至将这些置于 STL 所追求的原始、无管理性能之上。其目标是在 C++ 的环境中营造一种更接近“托管”语言的开发体验,为应用程序开发者减少常见的 C++ 陷阱。例如,自动初始化避免了因未初始化变量而导致的未定义行为,而隐式共享则使得以值传递大型容器的成本变得极低,鼓励了一种更安全、更易于理解的编程范式。
1.3. 二进制兼容性原则(ABI 稳定性)
Qt 拥有自己容器库的一个关键且更为深层的原因,是需要在不同版本间保持稳定的应用程序二进制接口(Application Binary Interface, ABI)1。STL 的实现会因编译器甚至编译器版本的不同而存在显著差异,这使得在公共 API 中暴露 STL 类型而不破坏二进制兼容性成为不可能的任务 5。
ABI 稳定性不仅是一个技术细节,更是 Qt 作为一个商业级框架价值主张的基石。它允许开发者链接到更新的 Qt 小版本库,而无需重新编译自己的应用程序。这一点的实现逻辑如下:
- Qt 主要以预编译的二进制库形式分发。
- 如果 Qt 的公共 API 使用了 std::vector,那么该 std::vector 的内存布局和行为将由用于构建 Qt 库的特定编译器和标准库版本决定。
- 当用户使用不同的编译器或同一编译器的更新版本来编译他们的应用程序时,他们代码中的 std::vector 可能会有不兼容的内存布局。
- 将这个不兼容的 std::vector 传递给一个 Qt 函数,将导致程序崩溃或未定义行为。
- 通过提供自己的 QVector,Qt 完全控制了其内存布局和行为,从而保证任何受支持的编译器创建的 QVector 都可以安全地传递给预编译的 Qt 库。这种控制是 ABI 稳定性的本质。
1.4. “Qt 之道”:在 Qt 生态系统中的深度集成
Qt 容器与框架的其他部分紧密集成。它们可以使用 QDataStream 进行流式传输 6,可以存储在QVariant 中,用于信号与槽机制,并且是许多 Qt API 函数的标准返回类型 11。
这种深度集成创建了一个强大且自洽的开发生态系统,但同时也形成了一座“围墙花园”。在 Qt 应用程序中使用 Qt 容器是无缝且必要的 11,但这增加了集成非 Qt C++ 代码或未来将应用程序的业务逻辑从 Qt 迁移出去的难度 14。这确立了“Qt 之道”的核心架构权衡:内部的一致性和便利性,与外部的可移植性和标准化之间的取舍。对于完全投入 Qt 生态的开发者来说,这种集成是巨大的优势;而对于希望保持核心逻辑框架无关性的项目来说,这则是一个需要仔细管理的架构边界。
2. 架构基石:隐式共享与写时复制(COW)
本节将剖析 Qt 值类型类中最重要的架构特性。我们不仅将解释其工作原理,还将探讨这一设计选择对性能、API 设计和多线程编程产生的深远影响。
2.1. 工作机制:引用计数与 detach() 操作
隐式共享是一种写时复制(Copy-on-Write, COW)技术 15。一个 Qt 容器对象由一个指向共享数据块的指针组成,该数据块包含一个引用计数器和实际数据 16。当一个对象被复制时,仅仅是复制了指针并增加引用计数(这被称为“浅拷贝”)1。数据的“深拷贝”仅在对一个共享实例(引用计数大于 1)调用非const 成员函数时才会发生。这个深拷贝操作被称为 detach() 16。
这个机制是为什么以值方式传递大型 Qt 容器(如 QList 或 QString)的效率极高的根本原因,它是一项基础性的优化 21。Qt 使用原子操作来管理引用计数,这使得在多线程环境中对数据进行只读访问是线程安全的 15。
2.2. 性能影响:复制的经济学
隐式共享的主要好处是最大限度地减少了昂贵的深拷贝操作,从而降低了内存使用并提升了性能,尤其是在从函数返回容器或将其作为参数传递时 11。这种设计鼓励了一种基于值的编程风格,这种风格通常比管理指针或引用更安全、更易于推理,同时又避免了 C++ 中值语义通常带来的性能开销 21。
例如,一个函数返回一个大的 QList,在没有隐式共享的情况下,这将触发整个列表的深拷贝。而有了隐式共享,返回操作的成本几乎为零,只涉及指针的复制和引用计数的增加。只有当调用者需要修改返回的列表时,才会产生实际的数据复制成本。
2.3. 隐藏的性能陷阱:COW 与现代 C++
C++11 引入的基于范围的 for 循环在用于非 const 的 Qt 容器时,会触发一次 detach() 操作。其背后的原因是,循环机制会调用容器的非 const 版本的 begin() 和 end() 方法。为了保证安全性,这些方法必须假设循环体内可能会发生写操作,因此如果容器是共享的,就会预先执行一次深拷贝 24。
相比之下,Qt 自有的 Q_FOREACH 宏(现已不推荐使用)通过在内部创建容器的一个 const 副本,从而调用非分离的 const 版本 begin() 和 end(),巧妙地避开了这个问题 25。这是 Qt 的历史架构与 C++ 语言演进之间的一个关键不匹配点。一个为方便而生的现代 C++ 特性,在与 Qt 容器天真地结合使用时,却成了一个无声的性能杀手。这并非一个 bug,而是两种不同设计哲学碰撞的直接后果。
其具体逻辑如下:
- 一个基于范围的 for 循环,如 for (auto& item : myContainer),是使用 myContainer.begin() 和 myContainer.end() 的循环的语法糖 28。
- 如果 myContainer 不是 const 的,编译器将调用 begin() 和 end() 的非 const 重载版本。
- Qt 的 COW 设计原则是,对共享对象的任何非 const 操作都必须触发 detach,以保持其他共享实例的值语义 17。
- 因此,在一个共享的、非 const 的 QList 上调用 myContainer.begin() 会强制对整个容器进行深拷贝,即使循环体只是读取数据。
- 这完全抵消了隐式共享带来的好处,并可能在紧凑循环或处理大型容器时导致灾难性的性能下降。
2.4. 最佳实践:qAsConst和std::as_const的重要作用
C++11 范围for循环:这是一个非常常见的陷阱。对一个非const的隐式共享容器(如QVector, QString)进行范围for循环,会隐式调用非const的迭代器,这会立即触发detach(),导致深拷贝。解决方案是使用常量引用进行迭代。在 Qt 6 (及 C++17 环境) 中,首选的、标准化的方法是使用 std::as_const。
QString original = "Some long shared string";
QString copy = original; // 共享数据
// 错误的方式:这将导致'original'发生不必要的拷贝
// for (const QChar &c : original) { ... }
// 正确且推荐的方式 (C++17+)
for (const QChar &c : std::as_const(original)) {
// ...
}
// Qt 5 或旧代码中常见的方式
// for (const QChar &c : qAsConst(original)) { ... }
对于旧项目或在 C++17 之前的环境,qAsConst() 仍然是有效的解决方案。
3. 顺序容器分析
本节将深入探讨 Qt 的类数组容器,重点关注 QList 和 QVector 的重大演变,并阐明它们在现代 Qt 6 开发中的角色。
3.1. QList 与 QVector 的演变史
在 Qt 4 和 Qt 5 中,QList 和 QVector 之间存在显著且常常令人困惑的差异。QVector<T> 保证了连续的内存存储,类似于 std::vector 19。而QList<T> 则是一个高度优化的指针数组。对于尺寸 T 大于指针尺寸(即sizeof(T) > sizeof(void*))的类型,QList 会存储 T* 并在堆上单独分配每个元素。对于较小的类型,它会直接存储元素值 1。
这导致了复杂的性能权衡。QList 由于在其内部数组的前端预留了空间,可以提供更快的头部添加操作(摊销 O(1))30,但对于大型类型,其在堆上的逐个分配可能非常缓慢 34。因此,官方的推荐用法也从 Qt 4 中的QList 转变为 Qt 5 中将 QVector 作为默认选择 1。
Qt 5 中的 QList 实现是一种复杂的优化,试图成为一个“一刀切”的通用容器。然而,它的行为并不直观(取决于 s i z e o f ( T ) sizeof(T) sizeof(T)),依赖于平台(32位 vs 64位 void*),并在社区中引发了无休止的争论和困惑。这是一个“聪明”的解决方案,但最终被证明对于通用目的而言过于复杂和不可预测。
3.2. Qt 6 的统一:清晰与性能
在 Qt 6 中,这一困惑得到了解决。QList 和 QVector 被统一了。现在 QVector 只是 QList 的一个 typedef(别名)1。两者的底层实现现在都是旧QVector 的实现——一个连续的动态数组 6。
这是 Qt 6 中最重要的架构简化之一。它消除了开发者困惑和潜在性能陷阱的一个主要来源。现在的建议是明确的:使用 QList 作为默认的顺序容器。它提供了 std::vector 的性能特征(连续内存、快速随机访问、摊销 O(1) 尾部添加),并结合了 Qt 的特性,如隐式共享。历史上的争论现在已经没有意义了。
3.3. QLinkedList 与 std::list 的选择
Qt 曾提供 QLinkedList 作为真正的双向链表实现,如果你拥有指向某个位置的迭代器,它可以在列表的中间提供 O(1) 的插入/删除时间 9。其一个关键特性是,只要元素存在,指向该元素的迭代器就保持有效 8。
然而,在 Qt 6 的文档中,现在明确建议如果需要真正的链表,应使用 std::list 6。这一变化反映了 Qt 6 的一个更广泛的趋势:在 STL 提供了完美、标准的解决方案,并且没有强烈的“Qt 特定”理由(如 COW 或QDataStream 集成)来维护一个独立实现的情况下,倾向于使用标准库。这简化了 Qt Core 库,并鼓励开发者在适当的地方使用标准的 C++ 结构。
3.4. 容器适配器:QStack 与 QQueue
QStack 和 QQueue 是提供 LIFO(后进先出)和 FIFO(先进先出)语义的便利类 6。它们分别作为QList(在 Qt 6 中)或历史上 QVector/QList 的子类实现 6。这些是薄封装层,为特定用例提供了更具表达力的 API(push/pop 用于栈,enqueue/dequeue 用于队列)6。它们是std::stack 和 std::queue 的直接对应物 1。
以下是 Qt 顺序容器及其常见操作的算法复杂度总结:
| 操作 | QList<T> (Qt 6) | std::list<T> / QLinkedList<T> |
|---|---|---|
| 随机访问 | O(1) | O(n) |
| 尾部插入/删除 | 摊销 O(1) | O(1) |
| 头部插入/删除 | O(n) (Qt 6) / 摊销 O(1) (Qt 5) | O(1) |
| 中间插入/删除 | O(n) | O(1) (需迭代器) |
4. 关联容器分析
本节将比较和对比 Qt 的键值容器,重点关注其底层数据结构所带来的根本性性能和功能差异。
4.1. QMap:有序字典
QMap<Key, T> 是一个关联容器,它以键的排序顺序存储键值对 38。它的实现基于平衡二叉搜索树(在 Qt 5 及更高版本中是红黑树,之前在 Qt 4 中是跳表)40。查找、插入和删除操作具有对数时间复杂度,即O(logn) 43。
Key 类型必须提供 operator<() 以便排序 6。
QMap 是在需要按键排序迭代,或者需要查找“下一个”或“上一个”键(例如,使用 lowerBound、upperBound)时的正确选择。它的有序性保证了遍历结果是可预测和确定的。
4.2. QHash:高速查找表
QHash<Key, T> 是一个提供比 QMap 快得多的查找速度的关联容器 6。它的实现是一个哈希表 40。查找、插入和删除操作具有平均(摊销)常数时间复杂度,即 O(1)。在大量哈希冲突的情况下,最坏情况的复杂度是 O(n) 43。
Key 类型必须提供 operator==() 和一个全局的 qHash(Key) 函数 38。
除非明确需要键的排序,否则 QHash 应该是关联容器的默认选择。对于大多数字典式的查找场景,其性能优于 QMap。
4.3. 性能的细微差别:QMap 何时可能更快
基准测试表明,对于非常少量的元素(例如,少于约 20 个),QMap 实际上可能比 QHash 更快 40。这个反直觉的结果源于哈希机制本身的开销。
其背后的逻辑是:
- QHash 的查找操作包括计算键的哈希值,然后在哈希表中找到对应的桶。虽然理论上是 O(1),但这涉及一次函数调用 (qHash) 和一些整数运算。
- QMap 的查找操作涉及在遍历二叉树时进行一系列的键比较 (operator<())。这是 O(logn) 的。
- 当 n 非常小时,QHash 中哈希计算的常数因子开销可能大于 QMap 的 O(logn) 搜索中几次比较所花费的总时间。例如,log2(16) 仅为 4 次比较。
- 因此,只有当容器增长到足够大,以至于 QMap 的 O(logn) 因子超过了 QHash 的常数因子开销时,QHash 的算法优势才会显现出来。
4.4. QSet 与多值容器
- QSet<T> 提供了一个具有快速查找功能的数学集合,其内部使用 QHash 实现 6。它类似于 std::unordered_set。
- QMultiMap 和 QMultiHash 是 QMap 和 QHash 的变体,允许将多个值与单个键关联 6。它们分别类似于std::multimap 和 std::unordered_multimap。
以下是 Qt 关联容器及其常见操作的算法复杂度总结:
| 操作 | QMap<Key, T> | QHash<Key, T> |
|---|---|---|
| 查找 | O(logn) | 平均 O(1), 最坏 O(n) |
| 插入 | O(logn) | 平均 O(1), 最坏 O(n) |
| 删除 | O(logn) | 平均 O(1), 最坏 O(n) |
5. 遍历策略:迭代器与循环
本节探讨遍历 Qt 容器的不同方式,重点介绍它们各自的优缺点,以及向标准 C++ 实践演进的关键过程。
5.1. 两种迭代器范式
Qt 容器提供了两种风格的迭代器,它们在概念和用法上有所不同。
STL 风格迭代器
自 Qt 2.0 起就已提供,这些迭代器模仿 C++ 指针的行为(例如 ++it, *it),并直接指向容器中的一个项目 6。它们是最高效的迭代方式,并且与 Qt 和 STL 的通用算法兼容 6。由于其类似指针的性质,它们非常轻量和快速 46。这是现代 Qt 开发中推荐的迭代方式。
Java 风格迭代器
在 Qt 4 中引入,这些迭代器提供了一个更高级别的 API(例如 hasNext(), next()),并且指向项目之间的位置 8。它们的设计初衷是为了更易用、更安全,但代价是轻微的性能损失 8。Qt 6 的文档现在推荐使用 STL 风格的迭代器,并指出 Java 风格的迭代器是为了向后兼容而保留的 6。Java 风格迭代器代表了过去一种试图抽象掉指针概念的设计哲学,而现在向 STL 风格迭代器的转变,是 Qt 拥抱标准 C++ 习语的又一例证。
以下是两种迭代器模型的对比:
| 特性 | STL 风格迭代器 | Java 风格迭代器 |
|---|---|---|
| 概念模型 | 指向项目本身(类指针) | 指向项目之间 |
| 语法 | *it, ++it, it->member | it.next(), it.hasNext() |
| 性能 | 最高效 | 略低 |
| 与通用算法的兼容性 | 与 Qt 和 STL 算法兼容 | 不兼容 |
| 主要弱点 | 迭代器失效规则严格 | API 较为冗长 |
| 现代推荐 | 推荐使用 | 为向后兼容而保留 |
5.2. 迭代器失效规则
对于两种迭代器类型,一个关键规则是:当容器的数据被修改,或由于调用非 const 成员函数而发生 detach() 时,迭代器会失效 6。在迭代过程中修改容器是导致错误的常见原因 46。这种行为类似于std::vector 等 STL 容器,但在 Qt 中,由于隐式共享机制,情况更为复杂。一个不明显的容器副本就可能使原始容器上的迭代器失效。这再次强调了在迭代期间应避免修改容器的准则。
5.3. Q_FOREACH 的弃用
Q_FOREACH 是 Qt 在 C++11 之前为简化迭代而提供的解决方案。现在它已被弃用,并正从 Qt 代码库中被基于范围的 for 循环所取代 27。它的关键行为是总是对其迭代的容器进行一次复制 27。得益于 COW,这对于 Qt 容器来说成本很低,但对于 STL 容器或QVarLengthArray 来说则代价高昂 27。
弃用 Q_FOREACH 不仅仅是为了采用新的 C++ 特性。它旨在解决该宏带来的不一致性和隐藏成本。虽然它巧妙地避免了迭代时的 detach 问题,但其强制复制对于非 COW 容器是一个性能陷阱,并且其“安全的”迭代时修改行为常常令人困惑,导致代码难以推理 27。C++11 基于范围的for 循环,尽管在与 Qt 容器结合使用时有其自身的陷阱(见 2.3 节),但在正确使用时,提供了一种更标准、更透明且最终更优越的机制。
6. 对比框架:Qt 容器 vs. C++ 标准库
本节提供了一个结构化的、直接的比较,超越了简单的映射,分析了指导开发者选择的更深层次的哲学和实践差异。
6.1. API 的对等与分歧
Qt 容器提供了一套双重 API:一套是“Qt 风格”的 API(如 append, count, isEmpty),另一套是“STL 兼容”的 API(如 push_back, size, empty)10。为了保持一致性,项目应该选择一种 API 风格并坚持使用。对于混合使用 Qt 和非 Qt 代码的项目,推荐使用 STL 兼容的 API,以简化过渡并保持统一的编码风格 1。此外,Qt 容器还提供了许多其 STL 对应物所没有的便利函数(例如QStringList::join, QList::contains)1。
6.2. 功能差距:STL 提供而 Qt 不提供的功能
- 只移类型 (Move-Only Types):Qt 容器不能存储只移类型(如 std::unique_ptr),因为隐式共享机制要求对象是可复制构造和可复制赋值的 1。这在大量使用移动语义的现代 C++ 中是一个显著的限制。
- 范围构造/插入 (Range Construction/Insertion):STL 容器可以从另一个容器类型的一对迭代器来构造或插入元素(例如 std::vector<int> v(my_set.begin(), my_set.end()))。Qt 容器缺乏这种通用的能力 1。
- 自定义分配器 (Custom Allocators):STL 容器接受一个 Allocator 模板参数,允许使用高级内存管理技术,如池分配器或将容器放置在共享内存中。Qt 容器不支持此功能 10。
- 异常安全 (Exception Safety):Qt 默认情况下通常在禁用异常的情况下编译,其容器不提供与 STL 容器相同的异常安全保证。
- 调试支持 (Debugging Support):大多数 STL 实现都带有强大的调试模式,可以在运行时检测常见的迭代器相关错误(例如,使用失效的迭代器)。Qt 容器缺乏类似的原生调试基础设施 10。
6.3. Qt 的独特优势
- 隐式共享 (Implicit Sharing):如前所述,这是 Qt 的旗舰特性,实现了高效的值传递语义。
- QDataStream 集成:所有 Qt 容器都可以直接通过 QDataStream 进行序列化和反序列化,这对于保存和加载应用程序状态非常方便 6。
- 框架内聚性 (Framework Cohesion):使用 Qt 容器可以与框架的其余 API 无缝集成,避免了在容器类型之间进行昂贵或繁琐的转换 11。
以下是 Qt 容器与其最接近的 STL 对应物的映射及关键差异:
| Qt 容器 | 最接近的 STL 对应物 | 关键架构差异 |
|---|---|---|
| QList<T> (Qt 6) | std::vector<T> | 隐式共享 (COW);API 更丰富;使用 int 作为大小类型 |
| QLinkedList<T> | std::list<T> | 隐式共享 (COW);Qt 6 推荐直接使用 std::list |
| QMap<Key, T> | std::map<Key, T> | 隐式共享 (COW);基于红黑树,保证键有序 |
| QHash<Key, T> | std::unordered_map<Key, T> | 隐式共享 (COW);基于哈希表,无序,查找更快 |
| QSet<T> | std::unordered_set<T> | 隐式共享 (COW);内部由 QHash 实现 |
| QMultiMap<Key, T> | std::multimap<Key, T> | 隐式共享 (COW);允许重复键,有序 |
| QMultiHash<Key, T> | std::unordered_multimap<Key, T> | 隐式共享 (COW);允许重复键,无序 |
| QStack<T> | std::stack<T> | 隐式共享 (COW);便利的 QList 子类 |
| QQueue<T> | std::queue<T> | 隐式共享 (COW);便利的 QList 子类 |
6.4. 做出选择:项目级策略
在选择使用 Qt 容器还是 STL 容器时,应遵循以下指导原则:
- 在与 Qt 框架紧密耦合的代码中(例如,GUI 代码、模型/视图类),使用 Qt 容器几乎总是正确且最实际的选择 11。这可以充分利用框架的集成优势,避免不必要的转换。
- 对于应保持可移植且独立于 UI 框架的后端逻辑、库或性能关键的计算代码,优先选择 STL 容器是一个合理的架构决策 24。这有助于实现清晰的关注点分离,防止核心逻辑与 Qt 不必要地绑定。
7. 结论与实践建议
本节将整个报告的分析综合为一套可操作的指南和清晰的决策框架,供实践中的开发者和架构师参考。
7.1. Qt 6 的新格局:现代最佳实践总结
- 将 QList 作为默认顺序容器。QList/QVector 之争已成历史。
- 优先使用 QHash 而非 QMap。仅在明确需要键排序时才使用 QMap。
- 只使用 STL 风格的迭代器。将 Java 风格的迭代器视为维护旧代码的遗留特性。
- 强制在基于范围的 for 循环中使用 qAsConst(),以遍历非 const、可能共享的 Qt 容器,防止无声的性能下降。
- 当需要真正的链表时,使用 std::list。
7.2. 与非 Qt 代码的接口
在应用程序架构中建立清晰的边界。在这些边界处,根据需要进行 Qt 和 STL 容器之间的转换。Qt 容器为此提供了辅助函数(例如 QVector::fromStdVector, QList::toStdList)52。虽然存在转换成本,但为了清晰的架构,这通常是值得付出的代价。
7.3. 最终决策矩阵
下表提供了一个快速参考指南,用于根据常见需求选择合适的容器。
| 需求 | QList<T> (Qt 6) | std::list<T> | QMap<Key, T> | QHash<Key, T> |
|---|---|---|---|---|
| 最快的按索引随机访问 | ★★★ 推荐 | ★ 不推荐 | (不适用) | (不适用) |
| 保证键按顺序排序 | (不适用) | (不适用) | ★★★ 推荐 | ★ 不推荐 |
| 最快的键值查找(顺序无关) | (不适用) | (不适用) | ★★ 可行 | ★★★ 推荐 |
| 频繁在序列中间插入/删除 | ★ 不推荐 | ★★★ 推荐 | (不适用) | (不适用) |
| 与需要原生数组的 C API 交互 | ★★★ 推荐 | ★ 不推荐 | (不适用) | (不适用) |
| 存储只移类型 (Move-Only) | ★ 不推荐 | ★★★ 推荐 | ★ 不推荐 | ★ 不推荐 |
| 需要与 Qt API (信号/槽, QVariant) 无缝集成 | ★★★ 推荐 | ★ 不推荐 | ★★★ 推荐 | ★★★ 推荐 |
| 需要自定义内存分配器 | ★ 不推荐 | ★★★ 推荐 | ★ 不推荐 | ★★★ 推荐 |
图例:
- ★★★ 推荐: 该容器是此场景的最佳选择。
- ★★ 可行: 该容器可以工作,但可能有性能或功能上的妥协。
- ★ 不推荐: 该容器不适合此场景。
引用的著作
- Exploring Qt Containers - Qt and C++ Blog / Clean Qt, 访问时间为 九月 14, 2025, https://www.cleanqt.io/blog/exploring-qt-containers
- Why do big projects like Unreal Engine write their own container classes? - Stack Overflow, 访问时间为 九月 14, 2025, https://stackoverflow.com/questions/64158032/why-do-big-projects-like-unreal-engine-write-their-own-container-classes
- Why does Qt have a ‘Q’ version of standard C++ objects (e.g. QVector, QString, etc.)?, 访问时间为 九月 14, 2025, https://stackoverflow.com/questions/40350120/why-does-qt-have-a-q-version-of-standard-c-objects-e-g-qvector-qstring-e
- Why use QVector(Qt) instead of std::vector - c++ - Stack Overflow, 访问时间为 九月 14, 2025, https://stackoverflow.com/questions/5623218/why-use-qvectorqt-instead-of-stdvector
- Trying Qt. Seems great. What downsides am I missing? : r/cpp - Reddit, 访问时间为 九月 14, 2025, https://www.reddit.com/r/cpp/comments/5t7d6u/trying_qt_seems_great_what_downsides_am_i_missing/
- Container Classes | Qt Core | Qt 6.9.2, 访问时间为 九月 14, 2025, https://doc.qt.io/qt-6/containers.html
- Qt 4.7: Container Classes, 访问时间为 九月 14, 2025, https://ftp.nmr.mgh.harvard.edu/pub/dist/freesurfer/tutorial_versions/freesurfer/lib/qt/qt_doc/html/containers.html
- Container Classes - Qt - Developpez.com, 访问时间为 九月 14, 2025, https://qt.developpez.com/doc/5.14/containers/
- Container Classes | Qt Core 5.15.1, 访问时间为 九月 14, 2025, https://qthub.com/static/doc/qt5/qtcore/containers.html
- Understand the Qt containers | -Wmarc - WordPress.com, 访问时间为 九月 14, 2025, https://marcmutz.wordpress.com/effective-qt/containers/
- Thread: About STL containers and QT equivalent - Qt Centre Forum, 访问时间为 九月 14, 2025, https://www.qtcentre.org/threads/38630-About-STL-containers-and-QT-equivalent
- QList Class | Qt Core 5.7, 访问时间为 九月 14, 2025, https://stuff.mit.edu/afs/athena/software/texmaker_v5.0.2/qt57/doc/qtcore/qlist.html
- STL or Qt containers? - c++ - Stack Overflow, 访问时间为 九月 14, 2025, https://stackoverflow.com/questions/1668259/stl-or-qt-containers
- When writing a Qt application is good practice to ALWAYS prefer Qt function implementations, data types, and classes when they are available?, 访问时间为 九月 14, 2025, https://softwareengineering.stackexchange.com/questions/364404/when-writing-a-qt-application-is-good-practice-to-always-prefer-qt-function-impl
- Copy-on-write - Wikipedia, 访问时间为 九月 14, 2025, https://en.wikipedia.org/wiki/Copy-on-write
- Qt 4.7: Implicit Sharing, 访问时间为 九月 14, 2025, https://ftp.nmr.mgh.harvard.edu/pub/dist/freesurfer/tutorial_packages_centos6/centos6/freesurfer-fsl-matlab-Linux-centos6_x86_64-dev/freesurfer/lib/qt/qt_doc/html/implicit-sharing.html
- Implicit Sharing | Qt Core | Qt 6.9.2, 访问时间为 九月 14, 2025, https://doc.qt.io/qt-6/implicit-sharing.html
- Implicitly Shared Classes - Qt 4.3 - Документация - CrossPlatform.RU, 访问时间为 九月 14, 2025, http://doc.crossplatform.ru/qt/4.3.2/shared.html
- Qt 4.1: QVector Class Reference, 访问时间为 九月 14, 2025, https://neo.dmcs.p.lodz.pl/po/qt-tutorial/docs/qt/qvector.html
- Qt 4.1: QList Class Reference, 访问时间为 九月 14, 2025, https://lux.dmcs.p.lodz.pl/po/qt-tutorial/docs/qt/qlist.html
- Thread: Implicit sharing vs. c++ refereces - Qt Centre Forum, 访问时间为 九月 14, 2025, https://www.qtcentre.org/threads/8722-Implicit-sharing-vs-c-refereces
- What I love about Qt - Vishesh Handa, 访问时间为 九月 14, 2025, https://vhanda.in/blog/2010/02/what-i-love-about-qt/
- Implicit Sharing and Multi-Threading Problems | Folding-Hyperspace, 访问时间为 九月 14, 2025, http://www.folding-hyperspace.com/real-time-programming-tips/tip-15-implicit-sharing-and.html
- Thread: std vs qt containers, 访问时间为 九月 14, 2025, https://www.qtcentre.org/threads/63063-std-vs-qt-containers
- Qt containers and C++11 range-based loops - Daniel Vrátil’s blog, 访问时间为 九月 14, 2025, https://dvratil.cz/2015/06/qt-containers-and-c-11-range-based-loops/
- Using C++11 range-based for loop correctly in Qt - Stack Overflow, 访问时间为 九月 14, 2025, https://stackoverflow.com/questions/35811053/using-c11-range-based-for-loop-correctly-in-qt
- A porting guide to C++11 ranged for-loops: Goodbye, Q_FOREACH | KDAB, 访问时间为 九月 14, 2025, https://www.kdab.com/goodbye-q_foreach/
- Range-based for loop (since C++11) - cppreference.com - C++ Reference, 访问时间为 九月 14, 2025, https://en.cppreference.com/w/cpp/language/range-for.html
- Consider replacing all Q_FOREACH/foreach loops with the c++ range-based loops · Issue #1060 · lxqt/lxqt - GitHub, 访问时间为 九月 14, 2025, https://github.com/lxqt/lxqt/issues/1060
- QVector vs QList - c++ - Stack Overflow, 访问时间为 九月 14, 2025, https://stackoverflow.com/questions/6602036/qvector-vs-qlist
- QVector Class | Qt Core 5.7 - MIT, 访问时间为 九月 14, 2025, https://stuff.mit.edu/afs/athena/software/texmaker_v5.0.2/qt57/doc/qtcore/qvector.html
- QList vs QVector revisited - c++ - Stack Overflow, 访问时间为 九月 14, 2025, https://stackoverflow.com/questions/33609406/qlist-vs-qvector-revisited
- Qt5 Tutorial QList - 2020 - BogoToBogo, 访问时间为 九月 14, 2025, https://www.bogotobogo.com/Qt/Qt5_QList.php
- Sneak Preview: QList considered harmful - Wmarc - WordPress.com, 访问时间为 九月 14, 2025, https://marcmutz.wordpress.com/2010/07/29/sneak-preview-qlist-considered-harmful/
- Use Vector instead of QList… - Qt Forum, 访问时间为 九月 14, 2025, https://forum.qt.io/topic/123718/use-vector-instead-of-qlist
- QVector Class | Qt Core | Qt 6.9.2, 访问时间为 九月 14, 2025, https://doc.qt.io/qt-6/qvector.html
- QList Class | Qt Core | Qt 6.9.2, 访问时间为 九月 14, 2025, https://doc.qt.io/qt-6/qlist.html
- QHash Class | Qt Core | Qt Documentation (Pro) - Felgo, 访问时间为 九月 14, 2025, https://felgo.com/doc/qt/qhash/
- Qt 4.8: QMap< Key, T > Class Template Reference - DreamSworK, 访问时间为 九月 14, 2025, https://dreamswork.github.io/qt4/classQMap.html
- QMap vs. QHash: A small benchmark - Woboq, 访问时间为 九月 14, 2025, https://woboq.com/blog/qmap_qhash_benchmark.html
- QMap Class | Qt Core 5.7, 访问时间为 九月 14, 2025, https://stuff.mit.edu/afs/athena/software/texmaker_v5.0.2/qt57/doc/qtcore/qmap.html
- Qt5 Tutorial QMap - 2020 - BogoToBogo, 访问时间为 九月 14, 2025, https://www.bogotobogo.com/Qt/Qt5_QMap.php
- When faster is actually slower – Dave Smith’s Blog, 访问时间为 九月 14, 2025, https://thesmithfam.org/blog/2011/02/12/when-faster-is-actually-slower/
- QHash Class | Qt Core 5.7, 访问时间为 九月 14, 2025, https://stuff.mit.edu/afs/athena/software/texmaker_v5.0.2/qt57/doc/qtcore/qhash.html
- QHash: Any weak spots performance-wise, besides rehashing? Why not? - Stack Overflow, 访问时间为 九月 14, 2025, https://stackoverflow.com/questions/40125908/qhash-any-weak-spots-performance-wise-besides-rehashing-why-not
- Iterators - Qt Wiki, 访问时间为 九月 14, 2025, https://wiki.qt.io/Iterators
- Iterator Classes - CopperSpice API, 访问时间为 九月 14, 2025, https://www.copperspice.com/docs/cs_api/containers-iterators.html
- Java-style Iterators in Qt | Qt Core | Qt 6.9.2 - Qt Documentation, 访问时间为 九月 14, 2025, https://doc.qt.io/qt-6/java-style-iterators.html
- Qt5 Tutorial QListIterator - 2020 - BogoToBogo, 访问时间为 九月 14, 2025, https://www.bogotobogo.com/Qt/Qt5_QListIterator.php
- Why does Qt foreach create a copy of the container? - Stack Overflow, 访问时间为 九月 14, 2025, https://stackoverflow.com/questions/23612885/why-does-qt-foreach-create-a-copy-of-the-container
- QT-C++ vs Generic C++ and STL [closed] - Software Engineering Stack Exchange, 访问时间为 九月 14, 2025, https://softwareengineering.stackexchange.com/questions/195568/qt-c-vs-generic-c-and-stl
- Qt 4.8: QVector< T > Class Template Reference - DreamSworK, 访问时间为 九月 14, 2025, https://dreamswork.github.io/qt4/classQVector.html
- Qt 4.8: QList< T > Class Template Reference - DreamSworK, 访问时间为 九月 14, 2025, https://dreamswork.github.io/qt4/classQList.html
- QList Class | Qt Core 5.15.1, 访问时间为 九月 14, 2025, https://qthub.com/static/doc/qt5/qtcore/qlist.html
更多推荐



所有评论(0)