简介

 QVector是Qt的一个通用容器类。
 它将其项存储在相邻的内存位置,并提供快速地、基于索引的访问(QVector可以看做是一个封装了一个数组的模板类[],它内部维护一个数组,并且提供给外部一些访问的方法)。

QList/QLinkedList/QVector/QVarLengthArray选择讨论

 QList/QLinkedList/QVector/QVarLengthArray提供了类似的api和功能。它们通常可以互换,但在性能方面有所不同。下面有一些使用建议:

  1. 如果你不清楚用哪种容器,那么建议你使用QVector。QVector通常比QList有更好的性能,因为QVector总是将它的项按顺序存储在内存中,而QList在堆上分配项,除非sizeof(T)<=sizeof(void*),并且T已经使用Q_DECLARE_TYPEINFO声明为Q_MOVABLE_TYPE或Q_PRIMITIVE_TYPE。参阅QList优缺点。
  2. 不过QList在Qt API中普遍被用来传递参数和返回值。与这些API交互时,使用QList。
  3. 如果你确实需要一个真正的链表,它可以保证在链表中插入耗时为常数时间。并对项使用迭代器(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容器内存释放

  1. 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()可以检验)

  2. 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相关推荐

  1. 新一配:一篇看懂加油站产业链解决方案

    新一配:一篇看懂加油站产业链解决方案的文章 一.加油站市场规模 截至2018年9月,全国机动车保有量达3.22亿辆,机动车驾驶人达4.03亿人.在这庞大的汽车生活消费生态链中,加油是汽车消费必不可少的 ...

  2. 阿联酋外汇业务的监管宽松?一篇看懂如何在阿联酋做外汇交易!

    阿联酋外汇业务的监管宽松?一篇看懂如何在阿联酋做外汇交易! 因为互联网技术的高速发展,个体交易者现在可以通过国际银行或经纪人轻松地进入外汇市场.就每日交易量而言,外汇市场可以称之为是世界上最大的市场. ...

  3. 卡尔曼滤波,最最容易理解的讲解.找遍网上就这篇看懂了(转载)

    学习卡尔曼滤波看了4天的文章,硬是没看懂.后来找到了下面的文章一下就看懂了. 我对卡尔曼滤波的理解, 我认为,卡尔曼滤波就是把统计学应用到了滤波算法上. 算法的核心思想是,根据当前的仪器"测 ...

  4. 【Google 开发者大会】一篇看懂 TensorFlow 如何助力高效开发

    代码不止 精彩不断! 刚圆满结束的谷歌开发者大会, 为大家带来了 TensorFlow 机器学习专场技术演讲 那么 TensorFlow 有哪些新鲜出炉的技术优化呢? 点击下面视频,带你1分钟看懂机器 ...

  5. 卡尔曼滤波,最最容易理解的讲解.找遍网上就这篇看懂了.

    学习卡尔曼滤波看了4天的文章,硬是没看懂.后来找到了下面的文章一下就看懂了. 我对卡尔曼滤波的理解, 我认为,卡尔曼滤波就是把统计学应用到了滤波算法上. 算法的核心思想是,根据当前的仪器"测 ...

  6. pyqt5从子目录加载qrc文件_【JVM系统学习之路】一篇看懂类加载

    JVM系统学习之路系列演示代码地址:https://github.com/mtcarpenter/JavaTutorial 嗨喽,小伙伴大家好,我是小春哥,今天是打卡 [JVM系统学习之路] 的第二篇 ...

  7. d盘不能扩展卷_一篇看懂!Linux磁盘的管理(分区、格式化、挂载),LVM逻辑卷,RAID磁盘阵列...

    Linux中磁盘的管理(分区.格式化.挂载),LVM逻辑卷,RAID磁盘阵列 一.认识磁盘 1.什么是磁盘: 磁盘是一种计算机的外部存储器设备,由一个或多个覆盖有磁性材料的铝制或玻璃制的碟片组成,用来 ...

  8. 一篇看懂CVPR 2017五大研究前沿 | 腾讯AI Lab深度解析

    感谢阅读腾讯AI Lab微信号第二篇文章,我们将深度解析本届CVPR热门研究.第一部分是五大前沿领域的重点文章解析,包括低中层视觉.图像描述生成.3D视觉.计算机视觉与机器学习.弱监督下的图像识别等. ...

  9. 6000字思考!一篇看懂促销系统的底层逻辑

    本文由作者 晓东同学 发布于社区促销是电商产品的核心功能模块,但也是最难做好的功能模块.促销的类型丰富且复杂,随意搭配组合就能给用户打造多样化的促销场景,引导用户进行购买. 因此,很多产品经理擅长在产 ...

最新文章

  1. IE下实现全屏两方法
  2. Rspamd 将收到的spam/ham转了到指定邮箱
  3. Python--面向对象之组合
  4. android device monitor命令行窗口在哪里_Vulkan在Android使用Compute shader
  5. navicat 怎么调试存储过程_Navicat 执行存储过程
  6. Go 中string和int类型相互转换
  7. mybaits trim用法
  8. Id vs Instancetype
  9. 后端返回页面ajax的处理
  10. 【AI视野·今日CV 计算机视觉论文速览 第173期】Wed, 25 Dec 2019
  11. 【专栏精选】Assetbundle入门
  12. iphone个人热点无法开启_无法在 iPhone 上正常使用“个人热点”怎么办?
  13. 通过rss阅读器写blog
  14. 等你来战!“2020第三届上海交大-卫宁健康智慧医疗挑战赛”报名正式启动
  15. 框架学习之Spring 第四节 Spring集成JDBC组件开发
  16. 针对github权限导致hexo部署失败的解决方案
  17. CISP 考试教材《第 6 章 知识域:信息安全评估》知识整理
  18. 2022-2027年中国智能化设计行业发展前景及投资战略咨询报告
  19. 理解模块化和依赖管理(一)
  20. 计算机一级及格良好优秀有什么用,2019计算机一级多少分合格 一级证书有什么用...

热门文章

  1. 23-pytest-清空allure历史报告
  2. 彩虹六号计算机丢失,彩虹六号围攻干员及配件更新后消失的解决方法
  3. TIVA Launchpad编程解锁好盈天行者(20A)电调
  4. 通过PyTorch用DCGAN生成动漫头像
  5. Magento URL rewrite
  6. argb drgb_十六进制颜色转换ARGB/RGB
  7. android+触摸绘图,GitHub - lslwsjly/touchvg: 支持多点触摸的矢量绘图框架(iOS、Android、Windows)...
  8. python 汉字识别训练数据生成_中文识别数据集生成脚本
  9. Java(Spring拦截器、过滤器、AOP)
  10. Unity实战项目 ☀️| 教你如何在Unity中通过 代码获取 URL链接网页 的 标题 等各种信息✨