C++ QList vs QVector重访
我的问题基本上是何时选择C++ QList vs QVector重访,c++,qt,qt5,qlist,qvector,C++,Qt,Qt5,Qlist,Qvector,我的问题基本上是何时选择QVector以及何时选择QList作为您的Qt容器。我已经知道: Qt文档: 在大多数情况下,QList是正确的类。它基于索引的API比QLinkedList基于迭代器的API更方便,而且由于它在内存中存储其项的方式,它通常比QVector更快。它还可以在可执行文件中扩展到更少的代码 同样是这样写的,这是非常流行的问答:。它也支持QList 但是:在最近的2015年Qt世界峰会上,KDAB提出了“为什么QList有害”,基本上是这样的: 据我所知,在堆中分配新元素时
QVector
以及何时选择QList
作为您的Qt容器。我已经知道:
QList
都是低效的。每次添加新元素时,它都会调用new
(每个元素调用一次),与QVector
相比,这是效率低下的
这就是我现在试图理解的原因:我们是否应该选择
QVector
作为默认容器?QList是作为文档状态一般使用的最佳容器。如果元素类型的大小为sizeof(void*)
=====
QList默认情况下,如果您遇到性能问题,请使用*向量,并根据需要进行配置和更改。Qt将
QList
宣传为“万事通”,但这句话的另一半是“一无是处”。如果您计划在列表的两端追加内容,那么我认为QList
是一个很好的选择,因为QList
在列表前后都保留了空间,所以列表的两端都不超过一个指针。就是这样,我的意思是,就使用QList
的充分理由而言
QList
将自动将“大型”对象存储为指针,并在堆上分配对象,如果您是婴儿,这可能被认为是一件好事,因为婴儿不知道如何声明QVector
并使用动态分配。这不一定是件好事,在某些情况下,它只会增加内存使用量并增加额外的间接寻址。在我看来,明确你想要什么总是一个好主意,不管是指针还是实例。即使您确实想要堆分配,也最好自己分配,并简单地将指针添加到列表中,而不是构造一次对象,然后在堆上进行复制构造
Qt会在很多地方返回一个QList
,这会带来开销,例如在获取QObject
的子对象或搜索子对象时。在这种情况下,使用在第一个元素之前分配空间的容器是没有意义的,因为它是一个已经存在的对象列表,而不是您可能预先准备的对象。我也不太喜欢缺少resize()
方法
想象一下,在64位系统上有一个大小为9字节、字节对齐的对象。对于QList
来说,它“太多了”,因此它将使用8字节指针+CPU开销进行缓慢的堆分配+内存开销进行堆分配。它将使用两倍的内存和额外的间接访问,它几乎不会提供广告中所宣传的性能优势
至于为什么QVector
不能突然成为“默认”容器-你不会中途更改马-这是一个遗留的东西,Qt是一个如此古老的框架,尽管很多东西已经被弃用,但对广泛使用的默认值进行更改并不总是可能的,不是不破坏很多代码,或者产生不想要的行为。无论好坏,QList
很可能在整个Qt5中一直是默认的,也可能在下一个主要版本中。同样的原因是,Qt将继续使用“哑”指针,在智能指针成为必须的东西之后的几年里,每个人都在为普通指针有多糟糕以及如何永远不要使用它们而哭泣
也就是说,没有人强迫您在设计中使用QList
。没有理由不将QVector
作为默认容器。我自己在任何地方都不使用QList
,在返回QList
的Qt函数中,我只是将内容临时移动到QVector
中
此外,这只是我个人的观点,但我确实发现Qt中的许多设计决策没有必要有意义,无论是性能还是内存使用效率还是易用性,总体而言,有很多框架和语言喜欢推广他们的做事方式,不是因为这是最好的方式,但因为这是他们的方式
最后但并非最不重要的是:
对于大多数p
sizeof( T ) <= sizeof( void* )
=====
QList< T > = [1][1][1][1][1]
or
[2][2][2][2][2]
or
[3][3][3][3][3]
or
[4][4][4][4][4] = new T[];
sizeof( T ) > sizeof( void* )
=====
QList< T > = [4][4][4][4][4] = new T*[]; // 4 = pointer's size
| | ... |
new T new T new T
// QVector<DataType> internal structure
DataType* pArray = new DataType[100];
// QList<DataType> internal structure
DataType** pPointersArray = new DataType*[100];
{
// ...
cout << pArray[index]; //fast
cout << *pPointersArray[index]; //slow, need additional operation for dereferencing
// ...
}
{
// QVector swaping
DataType copy = pArray[index];
pArray[index] = pArray[index + 1];
pArray[index + 1] = copy; // copy object
// QList swaping
DataType* pCopy = pPointersArray [index];
pPointersArray[index] = pPointersArray [index + 1];
pPointersArray[index + 1] = pCopy; // copy pointer
// ...
}
[ | | | | | | | [ | | | | | | | [ ...
[b| padding [b| padding [b...