为什么QList没有resize()方法?

sas*_*alm 13 c++ qt qlist

我只是注意到QList没有resize方法,QVector例如,有一个方法.为什么是这样?是否有相同的功能?

Nem*_*ric 10

嗯,这是更通用的答案,但我希望你会看到,通过比较QList以及QVector为什么不需要手动扩展容器.

QList使用内部缓冲区来保存指向元素的指针(或者,如果元素小于指针大小,或者元素是共享类之一 - 元素本身),真实数据将保留在堆上.

在此期间,删除数据不会减少内部缓冲区(空白区域将通过移动左侧或右侧元素来填充,在开始和结束时留出空间以便以后插入).

附加项目,比如QVector将在数组末尾创建额外的新空间,并且由于不同于QVector实际数据不存储在内部缓冲区中,您可以在单个指令中创建大量空间,无论项目的大小是多少(不像QVector) - 因为你只是将指针添加到索引缓冲区.

例如,如果您使用的是32位系统(每个指针4个字节),并且您要存储50个项目QList,并且每个项目大小为1MB,QVector则需要将缓冲区大小调整为50MB,并且QList仅需要分配内部缓冲区200B的记忆.这是你需要调用resize()的地方QVector,但是QList没有必要,因为分配小块内存不成问题,因为分配50MB的内存.

但是,这有一个代价,这意味着你有时想要预先QVector而不是QList:对于存储在其中的单个项目QList,你需要在堆上另外一个alloc - 保持项目的实际数据(数据指针在内部缓冲区指向).如果要添加大于指针的10000个项目(因为,如果它可以适合指针,它将直接存储在内部缓冲区中),则需要10000个系统调用来为堆上的10000个项目分配数据.但是,如果你正在使用QVector,并且你打电话resize,你可以适应单个alloc调用中的所有项目 - 所以QList如果你需要大量的插入或追加,请不要使用,更喜欢QVector这样.当然,如果您使用QList存储共享类,则无需额外分配,这也QList更适合.

因此,QList对大多数情况更喜欢:

  1. 使用索引访问单个元素,访问项目将更快 QLinkedList
  2. 插入到列表的中间只需要移动指针来创建空间,并且比移动实际QVector数据更快.
  3. 无需手动保留或调整空间大小,因为空白空间将移动到缓冲区的末尾供以后使用,并且在数组中分配空间非常快,因为元素非常小,并且可以分配很多没有杀死你的记忆空间的空间.

不要在以下场景中使用它,并且更喜欢QVector:

  1. 如果需要确保数据存储在顺序存储器位置
  2. 如果您很少在随机位置插入数据,但是您在结尾或开始时附加了大量数据,这可能会导致大量不必要的系统调用,并且您仍需要快速索引.
  3. 如果您正在寻找(共享)替换简单数组,这些数组不会随着时间的推移而增长.

最后,请注意:( QListQVector)具有的reserve(int alloc)功能QList如果alloc大于内部缓冲区的当前大小,将导致内部缓冲区增长.然而,这并不会影响外部尺寸QList(size()总会返回列表中包含的元素的确切数目).

  • 虽然您的解释非常合理,但调用 `resize` 可能仍然很好,不是作为优化,而是作为缩小或增加列表的手段(并在必要时填写默认值),*因为您的算法/设计需要恰好 n 个元素的列表*。 (2认同)
  • 不它不是。`reserve` 反过来*只是一种优化,它并没有真正改变外部世界对列表的看法(元素的数量),而如果你真的希望列表改变它的 *external*,则使用 `resize`尺寸。如果`QList`没有`resize`(出于你描述的概念原因),那么如果你需要它,那你只是不走运。看到你提议用 `reserve` 作为 `resize` 的替代品,我会把我的赞成票搁置一旁,直到它被修复。 (2认同)

小智 7

我认为原因是因为QList不要求元素类型具有默认构造函数.因此,没有任何操作QList可以创建仅复制它们的对象.

但是如果你真的需要调整大小QList(无论出于什么原因),这里有一个能够做到这一点的功能.请注意,它只是一个便利功能,并没有考虑到性能.

template<class T>
void resizeList(QList<T> & list, int newSize) {
    int diff = newSize - list.size();
    T t;
    if (diff > 0) {
        list.reserve(diff);
        while (diff--) list.append(t);
    } else if (diff < 0) list.erase(list.end() + diff, list.end());
}
Run Code Online (Sandbox Code Playgroud)

  • 它应该是`list.reserve(newSize);` (4认同)