【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() << &list[i];

}

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

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

int v = list[i]; // O(1)

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

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

QList a = b; // O(1)

a[0] = 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
相关推荐
white-persist2 小时前
【攻防世界】reverse | tt3441810 详细题解 WP
java·c语言·开发语言·数据结构·c++·算法·安全
古城小栈2 小时前
Go + 区块链:模块化链节点开发实践
开发语言·golang·区块链
码luffyliu2 小时前
Go sync 标准库实战指南:吃透并发同步的核心工具
开发语言·后端·golang
qq_401700412 小时前
Qt 跨版本兼容指南正确重写QTcpServer:incomingConnection 以支持32/64 位及 Qt4/Qt5+
qt
草莓熊Lotso2 小时前
C++ 异常完全指南:从语法到实战,优雅处理程序错误
android·java·开发语言·c++·人工智能·经验分享·后端
init_23612 小时前
MPLS跨域optionA 配置案例
java·开发语言·网络
墨有6662 小时前
【C++ 入门】类和对象(中)
开发语言·c++
雪夜行人2 小时前
cobra命令行工具
开发语言·golang
王家视频教程图书馆2 小时前
C#使用 tcp socket控制台程序和unity客户端通信
开发语言·tcp/ip·c#