【Qt】为什么QList是数组

为什么QList是数组

结论:在 Qt5 / Qt6 中,QList 不是链表,而是一个披着 list 名字的顺序容器。

一、QList 的历史背景
1. 名字的误导性

QList 这个名字,本身就极具欺骗性。

  • C++ 世界里:list ≈ 链表
  • Qt 世界里:QList ≠ 链表(至少现在不是)

很多认知混乱,并不是程序员不行,而是 API 命名留下的历史债务。

2. Qt4 时代的 QList

在 Qt4 时代:

  • QList 对小对象做内嵌存储
  • 对大对象存指针
  • 行为介于数组和链表之间

当时它确实不像 QVector 那么"纯粹",也导致了大量口口相传的"经验结论"。

3. Qt5 / Qt6 的转折

为了性能和可预测性:

  • Qt5 起,QList 内部实现改为连续存储
  • 行为与 QVector 高度一致
  • 但 API 名字和接口被完整保留

于是诞生了今天这个局面:

实现已经变了,但大家的印象没更新。

二、QList 的真实本质
1. 内存模型

在 Qt5 / Qt6 中:

  • 元素存储在连续内存中
  • 支持随机访问 operator[]
  • 迭代器是 RandomAccessIterator

这三点中,只要成立一条,就已经可以否定"链表实现"。

2. 一个简单的自证方法

QList list;

list << 1 << 2 << 3 << 4;

for (int i = 0; i < list.size(); ++i)

{

​ qDebug() << &listi;

}

如果它是链表,地址不可能连续。

三、QList 的核心特性
1. 随机访问

int v = listi; // O(1)

这是 QList 与真正链表在语义上的决定性分水岭。

2. 隐式共享(Copy-On-Write)

QList a = b; // O(1)

a0 = newValue; // 触发 detach

特点:

  • 拷贝"看起来"很便宜
  • 写入时才发生真实拷贝

这是 Qt 框架层面非常重要的设计哲学,但不是免费午餐。

3. 插入 / 删除复杂度

list.insert(pos, value);

list.removeAt(pos);

  • 时间复杂度:O(n)
  • 会移动内存
  • 并不比 QVector 更擅长中间插入

因此:

用 QList 解决"频繁中间插入"的问题,是一个误判。

四、QList 的常见误用场景
1. 当成链表使用

QList<Node*> nodes;

// 期望中间插入很快

这是历史经验误导下最常见的错误。

2. 多线程下无锁读写

// 一个线程遍历

for (auto& v : list) {}

// 另一个线程 append

list.append(x);

隐式共享 不等于线程安全。

这是 Qt 项目里非常隐蔽、但后果严重的坑。

五、QList vs QVector
1. 行为对比
  • 连续内存:两者都是
  • 随机访问:两者都是
  • 中间插入:两者都是 O(n)
2. 关键差异
  • QVector:语义清晰、无历史歧义
  • QList:API 兼容性强、历史包袱重
3. 工程选择原则

新代码默认 QVector,QList 只为兼容存在。

六、什么时候还可以接受 QList

不是绝对不能用,而是使用场景极少。

  • 维护老 Qt 项目
  • 被动接收 Qt API 返回的 QList
  • 项目中已经大量使用 QList,且无性能/并发问题
七、结论
  1. QList 不是链表(Qt5 / Qt6)
  2. 不要用链表思维使用 QList
  3. 隐式共享在多线程下必须显式加锁
  4. QList 不适合并发队列
  5. 新代码优先 QVector
相关推荐
Sarvartha9 小时前
final 关键字
java·开发语言
程序员Sunday10 小时前
JavaScript 事件循环面试题,宏任务与微任务怎么执行|Sunday面试指南
开发语言·javascript·面试·校招·事件循环·程序员sunday
Quz10 小时前
QML 动画选择:GIF与Lottie 的区别,以及 Qt 6.8 与 6.11 的 Lottie 实现差异
qt
zhangzeyuaaa11 小时前
Ruby 多线程、GVL(GIL)与 Mutex 完全指南
开发语言·前端·ruby
谢亮_vipxieliang12 小时前
用 PHP 构建轻量级 REST API:从路由到鉴权的完整实践
开发语言·后端·php
思无邪6612 小时前
用 AI 做 JS 逆向:从抓包到复现的完整方法论
开发语言·javascript·人工智能
H.莓飛12 小时前
【数据结构】二叉树_OJ题
linux·开发语言·数据结构·算法
零基础12313 小时前
Ubuntu 常用命令汇总
linux·运维·开发语言
外收内放13 小时前
Python基础语法练习题(57-58)
开发语言·python
时间的拾荒人14 小时前
Qt 界面美化实战:QSS 样式表
开发语言·qt·面试