我只是注意到QList
没有resize
方法,QVector
例如,有一个方法。为什么是这样?有没有等效的功能?
4 回答
好吧,这是更通用的答案,但我希望您能通过比较QList
了解QVector
为什么不需要手动扩展容器。
QList 使用内部缓冲区来保存指向元素的指针(或者,如果元素小于指针大小,或者元素是共享类之一- 元素本身),真实数据将保存在堆上。
在此期间,删除数据不会减少内部缓冲区(空白空间将通过向左或向右移动元素来填充,在开头和结尾留出空间以供以后插入)。
追加项目,likeQVector
将在数组末尾创建额外的新空间,并且由于与 不同QVector
,实际数据不存储在内部缓冲区中,因此无论项目的大小如何,您都可以在单个指令中创建大量QVector
空间(不像) - 因为您只是将指针添加到索引缓冲区中。
例如,如果您使用 32 位系统(每个指针 4 个字节)并且您在 中存储 50 个项目QList
,并且每个项目是 1MB 大,QVector
则缓冲区需要调整为 50MB,并且QList
只需要分配 的内部缓冲区200B内存。这是您需要调用resize()
的地方QVector
,但QList
没有必要,因为分配小块内存没有问题,因为分配 50MB 内存。
但是,有一个代价,这意味着您有时想要优先QVector
选择QList
:QList
内部缓冲区指向)。如果要添加比指针大的 10000 个项目(因为如果它可以放入指针,它将直接存储在内部缓冲区中),您将需要 10000 次系统调用来为堆上的 10000 个项目分配数据。但是,如果您正在使用QVector
,并且您调用,则可以在单个 alloc 调用中容纳所有项目 - 因此,如果您需要大量插入或附加,resize
请不要使用,更喜欢这样做。当然,如果你正在使用QList
QVector
QList
存储共享类,不需要额外的分配,这再次使得QList
更合适。
因此,QList
在大多数情况下更喜欢它:
- 使用索引访问单个元素,访问项目会更快
QLinkedList
- 插入到列表中间只需要移动指针来创建空间,它比移动实际
QVector
数据要快。 - 无需手动预留或调整空间,因为空的空间会被移到缓冲区的末尾以备后用,并且在数组中分配空间非常快,因为元素非常小,可以分配很多的空间,而不会杀死你的内存空间。
不要在以下场景中使用它,并且更喜欢QVector
:
- 如果您需要确保您的数据存储在顺序内存位置
- 如果您很少在随机位置插入数据,但在末尾或开头追加大量数据,这会导致大量不必要的系统调用,您仍然需要快速索引。
- 如果您正在寻找不会随时间增长的简单数组的(共享)替代品。
最后,请注意:QList
(and QVector
) 具有如果大于内部缓冲区的当前大小reserve(int alloc)
会导致QList
' 的内部缓冲区增长的功能。alloc
但是,这不会影响外部大小(QList
将size()
始终返回列表中包含的元素的确切数量)。
我认为原因是因为QList
不需要元素类型具有默认构造函数。因此,没有任何操作QList
可以创建一个对象,它只复制它们。
但是,如果您真的需要调整 a 的大小QList
(无论出于何种原因),这里有一个函数可以做到。请注意,它只是一个便利功能,并没有考虑到性能。
template<class T>
void resizeList(QList<T> & list, int newSize) {
int diff = newSize - list.size();
T t;
if (diff > 0) {
list.reserve(newSize);
while (diff--) list.append(t);
} else if (diff < 0) list.erase(list.end() + diff, list.end());
}
wasle 答案很好,但它会多次添加同一个对象。这是一个实用函数,它将为智能指针列表添加不同的对象。
template<class T>
void resizeSmartList(QList<QSharedPointer<T> > & list, int newSize) {
int diff = newSize - list.size();
if (diff > 0) {
list.reserve(diff);
while (diff>0){
QSharedPointer<T> t = QSharedPointer<T>(new T);
list.append(t);
diff--;
}
}else if (diff < 0) list.erase(list.end() + diff, list.end());
}
对于没有智能指针的使用,以下内容会将不同的对象添加到您的列表中。
template<class T>
void resizeList(QList<T> & list, int newSize) {
int diff = newSize - list.size();
if (diff > 0) {
list.reserve(diff);
while (diff>0){
T t = new T;
list.append(t);
diff--;
}
}else if (diff < 0) list.erase(list.end() + diff, list.end());
}
另请记住,您的对象必须具有默认构造函数(在标头中使用 arg="someValue" 声明的构造函数),否则它将失败。
只需使用类似的东西
QList<Smth> myList;
// ... some operations on the list here
myList << QVector<Smth>(desiredNewSize - myList.size()).toList();
本质上,到处都有这些 ///方法to
,from
Vector
这使得在必要时以某种手动但微不足道且有效(我相信)的方式调整 Qt 容器的大小变得微不足道。List
Set()
另一种(1 或 2 线)解决方案是:
myList.reserve(newListSize); // note, how we have to reserve manually
std::fill_n(std::back_inserter(myList), desiredNewSize - myList.size(), Smth());
-- 那是为面向 STL 的人准备的 :)
有关有效QList::resize()
可能变得多么复杂的一些背景,请参阅: