一篇看懂QVector
简介
QVector是Qt的一个通用容器类。
它将其项存储在相邻的内存位置,并提供快速地、基于索引的访问(QVector可以看做是一个封装了一个数组的模板类[],它内部维护一个数组,并且提供给外部一些访问的方法)。
QList/QLinkedList/QVector/QVarLengthArray选择讨论
QList/QLinkedList/QVector/QVarLengthArray提供了类似的api和功能。它们通常可以互换,但在性能方面有所不同。下面有一些使用建议:
- 如果你不清楚用哪种容器,那么建议你使用QVector。QVector通常比QList有更好的性能,因为QVector总是将它的项按顺序存储在内存中,而QList在堆上分配项,除非sizeof(T)<=sizeof(void*),并且T已经使用Q_DECLARE_TYPEINFO声明为Q_MOVABLE_TYPE或Q_PRIMITIVE_TYPE。参阅QList优缺点。
- 不过QList在Qt API中普遍被用来传递参数和返回值。与这些API交互时,使用QList。
- 如果你确实需要一个真正的链表,它可以保证在链表中插入耗时为常数时间。并对项使用迭代器(iterator)而不是索引,那么你可以使用QLinkedList。
Note:QVector和QVarLengthArray都保证了兼容C语言的数组布局。但是QList没有这么做。如果你的应用程序必须与C API进行对接,那么这点可能需要注意。
Note:只要引用的项仍然在容器中,那么QLinkedList中的迭代器和QList分配在堆上的引用(heap-cllocating)将会一直存在。对QVector中的迭代器和引用和非堆分配的QList(non-heap-allocating)来说,情况相反。
QVector简单用法
下面是一个存储整数的QVector和存储QString的QVector的一个示例。
QVector<int> integerVector;QVector<QString> stringVector;
QVector将它的项存储在vector(数组)中。通常,vector在创建时会带一个初始大小,下面代码是一个包含200个元素的QVector:
QVector<QString> vector(200);
vector中的元素会被自动初始化成一个默认构造值(default-constructed value)。如果你想要使用其他的值初始化vector,就通过第二个参数将其传递给构造函数。
QVector<QString> vector(200, "Pass");
你还可以使用fill()来用某个值填充vector。
QVector使用从0开始(0-based)的索引,就像c++数组一样。要访问特定索引位置的项,可以使用操作符[]()。在非常量vector中,操作符[]()返回一个能被用作左值的引用:
if (vector[0] == "Lix")vector[0] = "xxx";
如果是只读访问(read-only),可以使用另一种写法at():
for (int i = 0; i < vector.size(); ++i) {if (vector.at(i) == "Alfonso")cout << "Found Alfonso at position " << i << endl;}
at()比操作符执行更快,因为他不会进行深拷贝(deep copy)。
访问存储在QVector的数据还可以使用data()。该函数返回指向vector中第一项的指针,你可以使用这个指针直接访问和修改vector中的元素。如果你需要将QVector传递给一个接受C++数组的函数,这个指针会很有用。
如果你想要查找vector中某个特定的值,使用indexOf()或者lastIndexOf()。前者从指定索引位置开始向前搜索,后者向后搜索。若找到匹配项,则返回匹配项索引。否则返回-1,例如:
int i = vector.indexOf("harumi");if (i != -1)cout << "First occurrence of Harumi is at position"<< i <<endl;
如果只是想检查vector是否包含某个值,使用contains()。如果想知道某个值在vector中出现的次数,可以使用count()。
QVector提供了增删查改函数:insert()/replace()/remove()/prepend()/append()。对于存储量大的vector,这些函数可能会比较慢(线性时间-linear time),除了append()和replace(),因为它们需要将vector中的许多项在内存中移动一个位置(这点可以参考数组,因为是连续的顺序表,若要在中间插入或移除数据,许多元素都得移动)。如果你想要一个提供快速插入、删除的容器类,那么可以使用QList或者QLinkedList。
和普通的c++函数不同,QVector可以通过调用resize()随时调整大小。如果新的大小大于旧的大小,QVector可能需要重新分配整个vector。QVector试图通过预分配两倍于实际数据需要的内存来减少重新分配。
如果你预先知道QVector包含多少项,那么你可以调用reserve(),要求QVector预先分配一定数量的内存。你还可以调用capacity()来查明QVector实际分配了多少内存。
Note:使用非const操作符和函数会导致QVector对数据进行深拷贝,这是由于隐式共享(implicit sharing)。
QVector存储的值类型必须是可分配的数据类型。这涵盖了大多数的数据类型,但是编译器不允许你将QWidget存储为值。取而代之的是,你可以存一个QWidget *。一些函数有额外的要求,例如,indexOf()和lastIndexOf()希望值类型支持==()运算符。这些需求是在每个函数的基础上进行编写的。
和其他的容器一样,QVector提供了java风格的迭代器(QVectorIterator和QMutableVectorIterator)和stl风格的iterator(QVector::const_iterator和QVector::iterator)。不过在实际运用中,很少用到,因为你可以在QVector中使用索引。
除了QVector,Qt也提供QVarLengthArray,这是一个非常低级的类,几乎没有优化。
QVector不支持inserting、prepending、replacing它自己的值。如果这么做会引起应用程序报错而中止。
实际运用注意
Qt容器内存释放
QVector::clear(),在Qt5.6之前,它会释放vector中的内存。但是从5.7开始,它的容量(QVector中维护的数组的空间)会被保留。要释放所有的容量,你可以这么做:
QVector<T> v ...;QVector<T>().swap(v);Q_ASSERT(v.capacity() == 0);
或者使用squeeze()。
v.clear();v.squeeze();
这点很重要,在QVector中添加元素,如果只是调用clear,不释放空间,那之后的使用过程中,它一直会占着容器中最大占用量时的空间。(第一次往容器中添加了100个元素,然后clear了,你第二次添加了50个元素,此时容器内数组还占着100个元素的空间,用vector.capacity()可以检验)
QVector存储的类型为指针的情况下,当QVector销毁时,存储的指针指向的空间并不会被释放,需要手动释放那些空间。比如可以这样使用:
for(int i = 0; i < v.size(); i++){if (v[i] != nullptr){delete v[i];v[i] = nullptr;}}v.clear();v.squeeze();
不过,Qt中提供了qDeleteAll专门用于清除容器的内存。可以往里面传入首尾迭代器或者容器来完全释放容器内存。
总结
QVector是Qt编程中常用的容器,对它有个大致的认识很重要。
一篇看懂QVector相关推荐
- 新一配:一篇看懂加油站产业链解决方案
新一配:一篇看懂加油站产业链解决方案的文章 一.加油站市场规模 截至2018年9月,全国机动车保有量达3.22亿辆,机动车驾驶人达4.03亿人.在这庞大的汽车生活消费生态链中,加油是汽车消费必不可少的 ...
- 阿联酋外汇业务的监管宽松?一篇看懂如何在阿联酋做外汇交易!
阿联酋外汇业务的监管宽松?一篇看懂如何在阿联酋做外汇交易! 因为互联网技术的高速发展,个体交易者现在可以通过国际银行或经纪人轻松地进入外汇市场.就每日交易量而言,外汇市场可以称之为是世界上最大的市场. ...
- 卡尔曼滤波,最最容易理解的讲解.找遍网上就这篇看懂了(转载)
学习卡尔曼滤波看了4天的文章,硬是没看懂.后来找到了下面的文章一下就看懂了. 我对卡尔曼滤波的理解, 我认为,卡尔曼滤波就是把统计学应用到了滤波算法上. 算法的核心思想是,根据当前的仪器"测 ...
- 【Google 开发者大会】一篇看懂 TensorFlow 如何助力高效开发
代码不止 精彩不断! 刚圆满结束的谷歌开发者大会, 为大家带来了 TensorFlow 机器学习专场技术演讲 那么 TensorFlow 有哪些新鲜出炉的技术优化呢? 点击下面视频,带你1分钟看懂机器 ...
- 卡尔曼滤波,最最容易理解的讲解.找遍网上就这篇看懂了.
学习卡尔曼滤波看了4天的文章,硬是没看懂.后来找到了下面的文章一下就看懂了. 我对卡尔曼滤波的理解, 我认为,卡尔曼滤波就是把统计学应用到了滤波算法上. 算法的核心思想是,根据当前的仪器"测 ...
- pyqt5从子目录加载qrc文件_【JVM系统学习之路】一篇看懂类加载
JVM系统学习之路系列演示代码地址:https://github.com/mtcarpenter/JavaTutorial 嗨喽,小伙伴大家好,我是小春哥,今天是打卡 [JVM系统学习之路] 的第二篇 ...
- d盘不能扩展卷_一篇看懂!Linux磁盘的管理(分区、格式化、挂载),LVM逻辑卷,RAID磁盘阵列...
Linux中磁盘的管理(分区.格式化.挂载),LVM逻辑卷,RAID磁盘阵列 一.认识磁盘 1.什么是磁盘: 磁盘是一种计算机的外部存储器设备,由一个或多个覆盖有磁性材料的铝制或玻璃制的碟片组成,用来 ...
- 一篇看懂CVPR 2017五大研究前沿 | 腾讯AI Lab深度解析
感谢阅读腾讯AI Lab微信号第二篇文章,我们将深度解析本届CVPR热门研究.第一部分是五大前沿领域的重点文章解析,包括低中层视觉.图像描述生成.3D视觉.计算机视觉与机器学习.弱监督下的图像识别等. ...
- 6000字思考!一篇看懂促销系统的底层逻辑
本文由作者 晓东同学 发布于社区促销是电商产品的核心功能模块,但也是最难做好的功能模块.促销的类型丰富且复杂,随意搭配组合就能给用户打造多样化的促销场景,引导用户进行购买. 因此,很多产品经理擅长在产 ...
最新文章
- IE下实现全屏两方法
- Rspamd 将收到的spam/ham转了到指定邮箱
- Python--面向对象之组合
- android device monitor命令行窗口在哪里_Vulkan在Android使用Compute shader
- navicat 怎么调试存储过程_Navicat 执行存储过程
- Go 中string和int类型相互转换
- mybaits trim用法
- Id vs Instancetype
- 后端返回页面ajax的处理
- 【AI视野·今日CV 计算机视觉论文速览 第173期】Wed, 25 Dec 2019
- 【专栏精选】Assetbundle入门
- iphone个人热点无法开启_无法在 iPhone 上正常使用“个人热点”怎么办?
- 通过rss阅读器写blog
- 等你来战!“2020第三届上海交大-卫宁健康智慧医疗挑战赛”报名正式启动
- 框架学习之Spring 第四节 Spring集成JDBC组件开发
- 针对github权限导致hexo部署失败的解决方案
- CISP 考试教材《第 6 章 知识域:信息安全评估》知识整理
- 2022-2027年中国智能化设计行业发展前景及投资战略咨询报告
- 理解模块化和依赖管理(一)
- 计算机一级及格良好优秀有什么用,2019计算机一级多少分合格 一级证书有什么用...
热门文章
- 23-pytest-清空allure历史报告
- 彩虹六号计算机丢失,彩虹六号围攻干员及配件更新后消失的解决方法
- TIVA Launchpad编程解锁好盈天行者(20A)电调
- 通过PyTorch用DCGAN生成动漫头像
- Magento URL rewrite
- argb drgb_十六进制颜色转换ARGB/RGB
- android+触摸绘图,GitHub - lslwsjly/touchvg: 支持多点触摸的矢量绘图框架(iOS、Android、Windows)...
- python 汉字识别训练数据生成_中文识别数据集生成脚本
- Java(Spring拦截器、过滤器、AOP)
- Unity实战项目 ☀️| 教你如何在Unity中通过 代码获取 URL链接网页 的 标题 等各种信息✨