;
Movie类可以放入QT容器中,第一,虽然Movie类的构造函数有两个参数,但都有默认值,Movie()写法是允许的,所以有默认构造函数;第二,Movie类没有显示定义拷贝构造函数和赋值操作符,但C++编译器会提供一个默认的实现。
2、迭代器
QT容器类提供了两种风格的迭代器:Java风格和STL风格。Java风格迭代器比较容易使用,STL风格迭代器则可以用在一些通用算法中,功能比较强大。
每一个容器类都有对应的迭代器:只读迭代器和读写迭代器。
Java风格迭代器
STL风格迭代器begin()函数返回指向第一个元素的STL风格的遍历器,而end()函数则会返回指向最后一个元素之后位置的STL风格的遍历器。
QList<double>::iterator i = list.begin();
while (i != list.end())
*i = qAbs(*i);
3、隐式数据共享
QT所有容器类以及其他类如:QByteArray、QBrush、QFont、QImage、QPixmap和QString都使用了隐式数据共享技术。隐式数据共享使得类在参数和返回值中使用传值方式相当高效。
为了正确使用隐式数据共享,需要建立一个良好的编程习惯。首先,对list或者vector使用at()函数而不是[]操作符进行只读访问。 原因是[]操作符既可以是左值又可以是右值,这让Qt容器很难判断到底是左值还是右值,而at()函数是不能作为左值的,因此可以进行隐式数据共享。其次,对于begin()、end()以及其他一些非const容器,在数据改变时QT会进行深复制,要尽可能使用const_iterator, constBegin()和constEnd()。
二、顺序存储容器
1、QVector
QVector类是一个提供动态数组的模板类。QVector<T>使用连续内存来保存数据项,分配所需内存的方式与动态内存分配的方式相比,减少了在时间和内存上的开销。
QVector<T>和其他QT容器、大部分值类型的类(包括 QString)一样,使用隐式共享。但拷贝一个QVector时,内部只是拷贝了一个指针和递增了引用计数,只有修改数据时,才会进行深拷贝,隐式共享也称写时复制。
隐式共享是QVector和std::vector<T>的主要区别。
QBasicAtomic类用于保存引用计数,支持原子操作(线程安全),确保隐式共享可以跨线程使用。 QT在不同架构下使用汇编语言来实现QBasicAtomic类。
为了避免每次容器增长时都分配内存, QVector<T> 会一次分配超过需要的内存。如果参数T是可拷贝类型(可以通过memcpy() or memmove()进行拷贝的对象,例如C++原类型和QT隐式共享类), QVector<T>使用 realloc()一次再分配 4096字节的增量。 这是因为现代操作系统当重新分配一个内存时并不拷贝整块数据,只是物理内存页面简单的重新排序,第一页和最后一页需要进行拷贝。
对于不可拷贝数据类型,QVector<T>以每次增长50%的方式,确保在频繁调用append()函数时平均算法复杂度为 O(n)。
如果用QVector<T>储存自定义的类型, QT会假定自定义数据类型是不可拷贝类型。对于自定义可拷贝的数据类型,可以使用 Q_DECLARE_TYPEINFO()宏来声明。
class MyClass
{
...
private:
MyClassPrivateData *data;
};
Q_DECLARE_TYPEINFO(MyClass, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO()宏也可用于其他容器,最典型的就是 QList<T>。如果自定义数据类型是没有定义构造函数和析构函数的POD类型,能够用memcpy 和memmove函数进行拷贝,可以用把自定义类型声明为元类型而不是可拷贝类型。
class MyClass
{
...
private:
int x;
int y;
};
Q_DECLARE_TYPEINFO(MyClass, Q_PRIMITIVE_TYPE);
如果T是元类型, QVector<T>不会调用构造函数和析构函数,对可拷贝类型的优化对元类型都有效。
QVector<T>提供了[]的重载,但对于只读操作,由于不需要深拷贝,使用at()函数的效率会较高。
QVector<double> v(2);
v[0] = 1.1;
v[1] = 1.2;
如果实现不知道vector的长度,可以创建一个空参数的vector,然后使用append()函数添加数据:
QVector<double> v;
v.append(1.1);
v.append(1.2);
QVector<T>重载了<<,可以直接使用<<操作符
QVector<double> v;
v << 1.1 << 1.2;
如果QVector<T>中的数据没有被显式地赋值,那么,数据项将使用加入类的默认构造函数进行初始化,如果是基本数据类型和指针,则初始化为0
QVector类的所有成员函数是可重入的。
QVector主要成员函数如下:
QVector()
QVector(int size)
QVector(int size, const T & value)
QVector(const QVector<T> & other)
QVector<T> fromList(const QList<T> & list)[static]
QList<T> toList() const
QVector与QList转换函数
QVector<T> fromStdVector(const std::vector<T> & vector)[static]
std::vector<T> toStdVector() const
QVector与std::vector转换函数
const_iterator constBegin() const
返回指向vector中第一个元素的STL风格的const迭代器
const_iterator constEnd() const
返回指向vector中最后一个元素的下一个的STL风格的const迭代器
bool QVector::contains ( const T & value ) const
Vector中如果有value元素则返回true
void QVector::append ( const T & value )
在vector尾部插入元素value
void QVector::prepend ( const T & value )
在vector的开始插入值为value的元素
const T & QVector::at ( int i ) const
返回vector中索引i的元素值
iterator QVector::begin ()
const_iterator QVector::begin () const
返回指向vector中第一个元素的迭代器
iterator QVector::end ()
const_iterator QVector::end () const
返回一个指向vector中最后元素的下一个的指针
int QVector::capacity () const
Vector中能够存储元素的最大值
int QVector::size () const
返回vector中存储的元素的数量
void QVector::resize ( int size )
设置vector的大小为size,如果size大于当前vector的大小,则在尾部增加元素,如果size小于当前vector的大小,则在尾部删除元素。
void QVector::clear ()
删除vector中所有的元素并释放所占内存
bool QVector::startsWith ( const T & value ) const
如果vector非空,第一个元素为value,返回true
bool QVector::endsWith ( const T & value ) const
如果vector非空,最后一个元素为value,返回true
int QVector::count ( const T & value ) const
int QVector::count () const
返回vector中值为value的元素的个数
T * QVector::data ()
const T * QVector::data () const
返回vector中存储数据的指针
const T * QVector::constData () const
返回一个指向vector中数据的const指针
bool QVector::empty () const
返回vector是否为空,兼容STL风格
bool QVector::isEmpty () const
返回vector是否为空
void QVector::insert ( int i, const T & value )
在vector中的i位置插入值为value的元素
void QVector::remove ( int i )
删除vector中位置i的元素
void QVector::insert ( int i, int count, const T & value )
在vector中位置i插入count个值为value的元素
void QVector::remove ( int i, int count )
在vector中删除从位置i开始的count个元素
2、QLinekedList
QLinkedList<T>提供一个双向链表,插入删除操作在常数时间完成。
虽然插入、删除操作是常数时间,但 QLinkedList<T>只有在对象数量超过200对象时才能看出优势。对于小于200个对象的链表, QList<T>提供更好的性能、耗费更小的内存。
QLinkedList<T>的优点是数据的插入和删除很快,但是随机位置值的访问会很慢。与QVector<T>不同,QLinkedList<T>并没有提供重载的[]操作符,只能使用append()函数,或者<<操作符进行数据的添加。
QLinkedList所有成员函数是可重入的。
QLinkedList主要成员函数如下:
QLinkedList::QLinkedList ()
QLinkedList::QLinkedList ( const QLinkedList<T> & other )
QLinkedList<T> QLinkedList::fromStdList(const std::list<T> & list)[static]
std::list<T> QLinkedList::toStdList () const
QLinkedList与std::list的转换函数
void QLinkedList::append ( const T & value )
在list尾部插入值为value的元素
void QLinkedList::prepend ( const T & value )
在list开头插入值为value的元素
iterator QLinkedList::insert(iterator before, const T & value)
在迭代器before指向的项的前面插入值为value的项,返回指向插入项的迭代器
3、QList
QList是典型的数组链表,不是真正意义上的链表。
根据参数T的不同, QList 有两种组织方式。通常情况下, QList 有一个指针数组用于保存用new操作符在堆上分配的对象的指针,使得在容器的中间插入和删除的速度比参数为不可拷贝类型的QVector快,因为指针是可以用内存拷贝。
QList<T>是一个同时拥有QVector<T>和QLinkedList<T>的大多数有点的顺序存储容器类。既可以像QVector<T>一样支持快速的随机访问,重载了[]操作符,提供了索引访问的方式;也可以像 QLinkedList<T>一样,支持快速的添加、删除操作。除非我们需要进行在很大的集合的中间位置的添加、删除操作,或者是需要所有元素在内存中必须连续存储,否则我们应该一直使用Qlist<T>。
为了确保下标访问速度,QList内部使用数组实现。
QList<T>有几个特殊的情况。一个是QStringList,这是 QList<QString>的子类,提供针对QString的很多特殊操作。QStack<T>和 QQueue<T>分别实现了数据结构中的堆栈和队列,前者具有push(), pop(), top()函数,后者具有enqueue(), dequeue(), head()函数。
QList所有成员函数是可重入的。
QList主要成员函数如下:
QList::QList ()
QList::QList(const QList<T> & other)
QList<T> QList::fromSet(const QSet<T> & set) [static]
QList<T> QList::fromStdList(const std::list<T> & list) [static]
QList<T> QList::fromVector(const QVector<T> & vector) [static]
QSet、std::list、QVector类型转换为QList
QSet<T> QList::toSet() const
std::list<T> QList::toStdList() const
QVector<T> QList::toVector() const
QList转换为QSet、std::list、QVector
void QList::append(const T & value)
在list尾部插入值为value的元素
void QList::append(const QList<T> & value)
在list尾部插入value链表
QStack继承自QVector,提供后入先出LIFO的栈式结构,在QVector的基础上增加了push()、pop()、top()成员函数。
QStack所有成员函数是可重入的。
QStack主要成员函数如下:
QStack::QStack()
T QStack::pop()
出栈操作,返回栈顶元素,删除栈顶元素
void QStack::push(const T & t)
压栈操作,添加元素t到栈顶
T & QStack::top()
const T & QStack::top() const
返回栈顶元素的引用
QQueue继承自QList,提供先入先出FIFO的队列结构,在QList的基础上增加了enqueue()、dequeue()、head()成员函数。
QQueue所有成员函数是可重入的。
QQueue主要成员函数如下:
QQueue::QQueue ()
T QQueue::dequeue ()
出队列操作,返回队列中头元素的值并删除
void QQueue::enqueue ( const T & t )
入队列操作,添加t到队列尾部
T & QQueue::head ()
const T & QQueue::head () const
返回队列头元素的引用
三、关联存储容器
关联存储容器中存储的一般是二元组,即键值对。QT提供两种关联容器类型:QMap<K, T>和QHash<K, T>。
1、QMap
QMap是一个以升序键顺序存储键值对的数据结构,QMap原型为QMap<K, T>模板。
QMap<Key, T>保存一个根据主键排序的链表(主键,值),提供 O(log n)的查找时间常数。 QMap<Key, T>内部使用的是一个跳表的数据结构, 与红黑树提供类似的算法复杂度和性能。早期版本的 QMap 用的是红黑树,但是跳表代码简洁、节省内存。
class QMap<K,T>,QMap中的键值对根据Key进行了排序,QMap中Key类型必须重载operator<。
QMap使用方法如下:
QMap<QString, int> map;
map.insert("key 2", 2);
map.insert("key 1", 1);
map.insert("key 0", 0);
QList<QString> kList = map.keys();
for(int i=0; i<kList.count(); i++)
qDebug() << kList[i];
QList<int> vList = map.values();
for(int i=0; i<vList.count(); i++)
qDebug() << vList[i];
QMapIterator<QString, int> it(map);
while( it.hasNext() )
it.next();
qDebug() << it.key() << " : " << it.value();
QMap使用注意:
通过Key获取value时:
Key存在时返回对应的value
Key不存在时返回值类型所对应的“零”值
插入键值对时:
key存在时更新value的值
Key不存在时插入新的键值对
QMap<K, T>是一种键-值对的数据结构,实际上使用跳表skip-list实现,按照K进行升序的方式进行存储。使用QMap<K, T>的insert()函数可以向QMap<K, T>中插入数据。
QMap<QString, int> map;
map.insert("eins", 1);
map.insert("sieben", 7);
map.insert("dreiundzwanzig", 23);
QMap<K, T>也重载了[]运算符,可以按照数组的赋值方式进行使用
map["eins"] = 1;
map["sieben"] = 7;
map["dreiundzwanzig"] = 23;
[]操作符同样也可以像数组一样取值。如果在一个非const的map中,使用[]操作符取一个不存在的Key的值,则这个Key会被自动创建,并将其关联的value赋予一个空值。如果要避免这种情况,请使用QMap<K, T>的value()函数:
QMap<K, T>中的K和T可以是基本数据类型,如int,double,可以是指针,或者是拥有默认构造函数、拷贝构造函数和赋值运算符的类。并且K必须要重载<运算符,因为QMap<K, T>需要按K升序进行排序。
QMap<K, T>提供了keys()和values()函数,可以获得键的集合和值的集合。这两个集合都是使用QList作为返回值的。
QMap所有成员函数是可重入的。
QMap主要成员函数如下:
QMap::QMap ()
QMap::QMap ( const QMap<Key, T> & other )
QMap::QMap ( const std::map<Key, T> & other )
std::map<Key, T> QMap::toStdMap () const
QMap转换为std::map
QList<Key> QMap::uniqueKeys () const
返回map中所有唯一的key的链表
QMultiMap继承自QMap,允许一个key索引多个value。
QMap所有成员函数是可重入的。
QMap主要的成员函数如下:
QMultiMap::QMultiMap ()
QMultiMap::QMultiMap ( const QMap<Key, T> & other )
QMap<Key, T>::const_iterator QMultiMap::constFind(const Key & key, const T & value) const
QMap<Key, T>::const_iterator QMultiMap::constFind(const Key & key) const
返回map中键为key的迭代器
bool QMultiMap::contains ( const Key & key, const T & value ) const
bool QMultiMap::contains ( const Key & key ) const
map中键是否存在键为key的键
int QMultiMap::count ( const Key & key, const T & value ) const
int QMultiMap::count ( const Key & key ) const
int QMultiMap::count () const
返回map中键为key的数量
int QMultiMap::remove ( const Key & key, const T & value )
int QMultiMap::remove ( const Key & key )
删除map中键为key的键值对
3、QHash
QHash是QT中的Hash数据结构,QHash原型类类模板QHash<K, T>。
QHash中的键值对在内部无序排列,key类型必须重载operator==,key对象必须重载全局哈希函数qHash()。
QHash使用方法如下:
QHash<QString, int> hash;
hash.insert("key 2", 2);
hash.insert("key 1", 1);
hash.insert("key 0", 0);
QList<QString> kList = hash.keys();
for(int i=0; i<kList.count(); i++)
qDebug() << kList[i];
QList<int> vList = hash