欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

一篇看懂QVector

程序员文章站 2022-05-13 15:00:02
...

简介

 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它自己的值。如果这么做会引起应用程序报错而中止。

实际运用注意

  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,那之后的使用过程中,它一直会占着容器中最大占用量时的空间。

总结

 QVector是Qt编程中常用的容器,对它有个大致的认识很重要。

相关标签: c++ qt