一、概念
QList是Qt的泛型容器类之一。它将数据存储在一个列表中,该列表提供基于索引的快速访问以及基于索引的插入和删除。
QList、QLinkedList 和 QVector 提供了类似的 API 和功能。它们通常是可互换的,但性能有所区别。(以前 QVector 在 Qt 5 中是一个不同的类,但现在是一个简单的 QList 别名)
QVector 应该是默认首选的容器
QList是最广泛用于Qt API中传递值的容器
QList不是指针结构体类型的链表,真正的结构体指针链表是 QLinkedList
二、存储的数据类型
QList可以保存基本数据类型的,如int,double,bool等;但是在存储QObject对象及其子类对象时,不能直接存对象本身,而是只能存对象的地址;

三、QList的相关接口:
1.初始化和构造
cpp
//1.默认构造
QList<int>list1;
//2.初始化列表构造
QList<int>list2 = {1,2,3,4};
//3.拷贝构造
QList<int>list3 = list2;
//4.指定大小和初始值
QList<int> list4;
list4 << 100 << 101 << 102 << 103; //4个元素,值都是100
2.添加元素
cpp
//1.append尾加
list5.append("DDD");
//2.prepend 头加
list5.prepend("000");
//3.insert 指定位置插入
list5.insert(2,"111");
//4.<<添加
list5<<"DDD"<<"EEE";
//5.+添加
list5 +={"DDD","EEE","FFF","GGG","FFF","AAA"};
3.访问元素
cpp
//1.[] 非const的方式访问,可修改
qDebug()<<"list5[0]:"<<list5[0];
//2.at 常量访问
qDebug()<<"list5.at(1):"<<list5.at(1);
//3.first第一个元素 last最后一个元素
qDebug()<<"list5.first():"<<list5.first()<<",last:"<<list5.last();
//4.value 安全访问,越界返回默认值
qDebug()<<"list5.value():"<<list5.value(5);
QString data = list5.value(10);//越界访问返回"";
qDebug()<<"list5.value(10):"<<list5.value(10);
qDebug()<<"list5.value(12):"<<list5.value(12,"UnKnown");//越界访问返UnKnown
4.修改元素
cpp
//1.通过索引修改
list5[0] = "ABB";
//2.replace 替换指定的位置
list5.replace(1,"bbb");
//3.swap交换两个位置的元素
std::swap(list5[1],list5[3]);
QList<QString> list6={"Apple","banana","orange","pear"};
list5.swap(list6);
//4.move移动元素到新的位置
list5.move(0,2);
5.删除元素
cpp
//1.removeAt 删除指定位置
list5.removeAt(0);
//2.removeFirst removeLast
list5.removeFirst();
list5.removeLast();
//3.removeOne 删除第一个匹配的元素
list5.append("AAA");
list5.removeOne("AAA");
//4.删除所有匹配的元素
list5.append("AAA");
list5.insert(5,"AAA");
list5.removeAll("AAA");
qDebug()<<"size:"<<list5.size();
//5.clear 清除所有
list5.clear();
qDebug()<<"size:"<<list5.size();
//6.takeAt 删除并返回该元素
QString at2 = list5.takeAt(2);
qDebug()<<"at2:"<<at2;
6.查找和查询
cpp
//1.contains - 是否包含
bool hasAaa = list5.contains("Aaa");
//2.indexof 查找第一次出现的位置
int index = list5.indexOf("Aaa");
int index2 = list5.indexOf("FFF");
qDebug()<<"hasAaa:"<<hasAaa<<", indexOf Aaa"<<index<<",indexOf FFF"<<index2;
//3.lastIndexOf - 查找最后一次出现的位置
int index3 = list5.lastIndexOf("FFF");
qDebug()<<"lastIndexOf FFF:"<<index3;
//4.count - 统计出现次数
int count = list5.count("FFF");
qDebug()<<"count FFF:"<<count;
//5.startsWith / endsWith 第一个/最后一个元素是否是某个值
bool bstart = list5.startsWith("FFF");
bool bstart2 = list5.startsWith("AAA");
bool bEnd = list5.endsWith("FFF");
bool bEnd2 = list5.endsWith("AAA");
qDebug()<<"bstart:"<<bstart<<","<<bstart2<<"bEnd:"<<bEnd<<","<<bEnd2;
7.容量相关
cpp
QList<QString> list5;
list5 << "AAA" << "BBB" << "CCC";
//1.size count length元素的个数
qDebug()<<"size:"<<list5.size()<<" count:"<<list5.count()<<" length:"<<list5.length();
//2.isEmpty 判空
qDebug()<<"isEmpty:"<<list5.isEmpty();
//capacity - 当前容量 QT6 List才新增的
list5.reserve(100);
qDebug() << list5.capacity();
//3.reserve预分配内存 预分配空间,避免频繁重新分配
list5.reserve(50);
qDebug()<<"reserve:"<<list5.size();
//4.resize 调整大小 QT6 List才新增的
list5.resize(5); // 大小变为5,新元素默认初始化
list5.resize(2); // 大小变为2,截断后面的元素
//5.squeeze释放多余内存 QT6 List才新增的
qDebug()<<"resize:"<<list5.size();
list5.squeeze(); // 将容量调整为实际大小
capacity容量 vs size大小
* size capacity容量
* reserve(50) 预订了50间房 0人入住 50间房可用
resize(50) 开了50间房并住满 50人入住 50间房
append(1) 1人入住,还有49间空房 1人入住 50间房
作用 使用场景
**reserve(n) 预分配 capacity 已知元素数量,优化性能
** resize(n) 设置size并初始化 需要立即访问 n 个元素
** append() 增加size并添加值 逐个添加元素
** size() 获取实际元素个数 遍历、检查是否为空
8.迭代器
cpp
//1.遍历下标
qDebug()<<"list1:"<<list1.size();
for(int i = 0; i< list2.size();i++)
qDebug()<<"list2:"<<list2[i];
//2.范围for遍历
for(const int &i:list3)
qDebug()<<"list3:"<<i;
//3.STL风格迭代器
QList<int>::iterator it;
for(it = list4.begin();it!=list4.end();it++)
{
*it = *it - 100;//可以修改元素
qDebug()<<"list4 it:"<<*it;
}
9.转换
cpp
QList<int>numbers1 = {1,2,3,6,8,99,90};
//tovector转换为QVector
QVector<int>vector = numbers1.toVector();
//或者直接比较内存地址看是否转换成功
bool success = (numbers1.size() == vector.size());
qDebug()<<"success1:"<<success;
for (int i = 0; success && i < numbers1.size(); ++i) {
success = (numbers1.at(i) == vector.at(i));
}
qDebug()<<"success2:"<<success;
//formvector 从QVector 转换
QList<int> newList = QList<int>::fromVector(vector);
qDebug()<<"formvector:"<<(newList == numbers1);
// toStdList - 转换为 std::list
std::list<int> stdList(numbers1.begin(), numbers1.end());
std::list<int>::iterator it1;
for(it1=stdList.begin();it1!=stdList.end();it1++)
qDebug()<<"stdList:"<<*it1;
四、QList的隐式共享:
QList本身是一个容器,它实现了隐式共享。这意味着当我们将一个QList赋值给另一个QList时,它们共享同一份数据,直到其中一个需要修改(写操作)时,才会进行深拷贝。
cpp
QList<int> list1 = {1, 2, 3, 4, 5};
//浅拷贝 - 共享数据
QList<int> list2 = list1;
qDebug() << "list1 地址:" << &list1 << "数据地址:"
<< (list1.isEmpty() ? nullptr : &list1[0]);
qDebug() << "list2 地址:" << &list2 << "数据地址:"
<< (list2.isEmpty() ? nullptr : &list2[0]);
// 修改 list2,触发写时复制
list2.append(6);
// 数据地址现在不同了
if (!list1.isEmpty() && !list2.isEmpty()) {
qDebug() << "list1 数据地址:" << &list1[0];
qDebug() << "list2 数据地址:" << &list2[0];
}
//打印信息
list1 地址: 0x2d837cf508 数据地址: 0x1fa1e205210
list2 地址: 0x2d837cf500 数据地址: 0x1fa1e203f10
//修改后
list1 数据地址: 0x1fa1e205210
list2 数据地址: 0x1fa1e1d6350
五、参考文档:
QList 类官方文档
Qt QList使用总结