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

时间:2022-09-29 07:18:40

I just noticed that QList doesn't have a resize method, while QVector, for example, has one. Why is this? And is there an equivalent function?

我刚刚注意到QList没有resize方法,而QVector有。这是为什么呢?有等价函数吗?

4 个解决方案

#1


7  

I think reason is because QList doesn't require the element type to have a default constructor. As a result of this, there is no operation where QList ever creates an object it only copies them.

我认为原因在于QList不要求元素类型具有默认构造函数。因此,在QList只复制一个对象的情况下,不存在任何操作。

But if you really need to resize a QList (for whatever reason), here's a function that will do it. Note that it's just a convenience function, and it's not written with performance in mind.

但是,如果您确实需要调整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());
}

#2


10  

Well, this is the more generic answer, but I hope you will see, by comparising QList and QVector why there is no need of manually expanding the container.

这是更一般的答案,但是我希望您通过比较QList和QVector来了解为什么不需要手动扩展容器。

QList is using internal buffer to save pointers to the elements (or, if the element is smaller than pointer size, or element is one of the shared classes - elements itself), and the real data will be kept on the heap.

QList使用内部缓冲区来保存指向元素的指针(或者,如果元素小于指针大小,或者元素是共享类中的一个元素本身),那么实际的数据将被保留在堆上。

During the time, removing the data will not reduce internal buffer (empty space will be filled by shifting left or right elements, leaving space on the beginning and the end for later insertions).

在此期间,删除数据不会减少内部缓冲区(空的空间将通过移动左或右元素来填充,在开始和结束处留下空间供以后插入)。

Appending items, like QVector will create additional new space on end of the array, and since, unlike QVector, real data is not stored in internal buffer, you can create a lot of space in single instruction, no matter what size of the item is (unlike QVector) - because you are simply adding pointers into indexing buffer.

附加项目,像QVector会创建额外的新空间的数组,因为,不像QVector,真正的数据不是存储在内部缓冲区,您可以创建很多空间在单指令,无论项目大小是什么(不像QVector)——因为你只是将指针添加到索引缓冲区。

For example, if you are using 32bit system (4 bytes per pointer) and you are storing 50 items in the QList, and each item is 1MB big, QVector buffer will need to be resized to 50MB, and QList's internal buffer is need to allocate only 200B of memory. This is where you need to call resize() in QVector, but in QList there is no need, since allocating small chunk of memory is not problematic, as allocating 50MB of memory.

例如,如果您正在使用32位系统(每个指针4字节),并且您正在QList中存储50个条目,并且每个条目的大小为1MB,那么QVector缓冲区将需要调整为50MB, QList的内部缓冲区只需要分配200B的内存。这就是需要在QVector中调用resize()的地方,但是在QList中没有这个必要,因为分配小块内存并没有问题,因为分配50MB内存。

However, there is a price for that which means that you sometimes you want to preffer QVector instead of QList: For single item stored in the QList, you need one additional alloc on the heap - to keep the real data of the item (data where pointer in the internal buffer is pointing to). If you want to add 10000 items larger than the pointer (because, if it can fit into pointer, it will be stored directly in the internal buffer), you will need 10000 system calls to allocate data for 10000 items on the heap. But, if you are using QVector, and you call resize, you are able to fit all the items in the single alloc call - so don't use QList if you need a lot of inserting or appending, prefer QVector for that. Of course, if you are using QList to store shared classes, there is no need for additional allocating, which again makes QList more suitable.

然而,有一个价格,这意味着你有时候要参照QVector代替QList:对于单项QList中存储,需要一个额外的分配在堆上,保持物品的真实数据(数据内部缓冲区指针是指向)。如果要添加比指针大的10000个项(因为,如果它可以装入指针,那么它将直接存储在内部缓冲区中),您将需要10000个系统调用来为堆上的10000个项分配数据。但是,如果您使用QVector,并且您调用resize,那么您就能够将所有的项都匹配到单个alloc调用中——因此,如果您需要大量插入或追加,那么不要使用QList,更喜欢使用QVector。当然,如果您正在使用QList来存储共享类,则不需要额外的分配,这也使QList更适合。

So, prefer QList for most of the cases as it is:

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

  1. Using indices to access the individual elements, accessing items will be faster that QLinkedList
  2. 使用索引访问单个元素,访问条目将比QLinkedList更快
  3. Inserting into middle of the list will only require moving of the pointers to create space, and it is faster than shifting actual QVector data around.
  4. 插入到列表的中间只需要移动指针来创建空间,这比移动实际的QVector数据要快。
  5. There is no need to manually reserve or resize space, as empty space will be moved to the end of the buffer for later use, and allocating space in the array is very fast, as the elements are very small, and it can allocate a lot of space without killing your memory space.
  6. 不需要手动储备或调整空间,空间将搬到缓冲供以后使用,和数组分配空间非常快,非常小的元素,它可以分配大量的空间没有杀死你的内存空间。

Don't use it in the following scenarios, and prefer QVector:

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

  1. If you need to ensure that your data is stored in the sequential memory locations
  2. 如果您需要确保数据存储在顺序内存位置
  3. If you are rarely inserting data at the random positions, but you are appending a lot of data at the end or beginning, which can cause a lot of unnecessary system calls, and you still need fast indexing.
  4. 如果您很少在随机位置插入数据,但是您在末尾或开头添加了大量数据,这可能导致大量不必要的系统调用,并且您仍然需要快速索引。
  5. If you are looking for (shared) replacement for simple arrays which will not grow over the time.
  6. 如果您正在寻找简单数组的(共享)替换,这些数组不会随时间增长。

And, finally, note: QList (and QVector) have reserve(int alloc) function which will cause QList's internal buffer to grow if alloc is greater than the current size of the internal buffer. However, this will not affect external size of the QList (size() will always return the exact number of elements contained in the list).

最后,注意:QList(和QVector)具有reserve(int alloc)函数,如果alloc大于内部缓冲区的当前大小,这会导致QList的内部缓冲区增加。但是,这不会影响QList的外部大小(size()总是会返回列表中包含的元素的确切数量)。

#3


0  

wasle answer is good, but it'll add the same object multiple time. Here is an utility functions that will add different object for list of smart pointers.

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());
}

For use without smart pointers, the following will add different objects to your list.

为了不使用智能指针,下面将向列表中添加不同的对象。

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());
}

Also remember that your objects must have default constructor (constructor declared in the header with arg="someValue") or else it will fail.

还要记住,对象必须具有默认构造函数(在标头中使用arg="someValue"声明的构造函数),否则它将失败。

#4


-3  

Just use something like

只使用类似

QList<Smth> myList;
// ... some operations on the list here
myList << QVector<Smth>(desiredNewSize - myList.size()).toList();

Essentially, there are these to/from Vector/List/Set() methods everywhere, which makes it trivial to resize Qt containers when necessary in a somewhat manual, but trivial and effective (I believe) way.

本质上,到处都有这些to/from向量/List/Set()方法,这使得在需要的时候以一种手工的、但简单而有效的方式(我相信)调整Qt容器的大小变得非常简单。

Another (1 or 2-liner) solution would be:

另一种(1或2-线性)解决方案是:

myList.reserve(newListSize); // note, how we have to reserve manually
std::fill_n(std::back_inserter(myList), desiredNewSize - myList.size(), Smth());

-- that's for STL-oriented folks :)

——面向stl的人:

For some background on how complex an effective QList::resize() may get, see:

要了解有效QList::resize()的复杂程度,请参见:

#1


7  

I think reason is because QList doesn't require the element type to have a default constructor. As a result of this, there is no operation where QList ever creates an object it only copies them.

我认为原因在于QList不要求元素类型具有默认构造函数。因此,在QList只复制一个对象的情况下,不存在任何操作。

But if you really need to resize a QList (for whatever reason), here's a function that will do it. Note that it's just a convenience function, and it's not written with performance in mind.

但是,如果您确实需要调整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());
}

#2


10  

Well, this is the more generic answer, but I hope you will see, by comparising QList and QVector why there is no need of manually expanding the container.

这是更一般的答案,但是我希望您通过比较QList和QVector来了解为什么不需要手动扩展容器。

QList is using internal buffer to save pointers to the elements (or, if the element is smaller than pointer size, or element is one of the shared classes - elements itself), and the real data will be kept on the heap.

QList使用内部缓冲区来保存指向元素的指针(或者,如果元素小于指针大小,或者元素是共享类中的一个元素本身),那么实际的数据将被保留在堆上。

During the time, removing the data will not reduce internal buffer (empty space will be filled by shifting left or right elements, leaving space on the beginning and the end for later insertions).

在此期间,删除数据不会减少内部缓冲区(空的空间将通过移动左或右元素来填充,在开始和结束处留下空间供以后插入)。

Appending items, like QVector will create additional new space on end of the array, and since, unlike QVector, real data is not stored in internal buffer, you can create a lot of space in single instruction, no matter what size of the item is (unlike QVector) - because you are simply adding pointers into indexing buffer.

附加项目,像QVector会创建额外的新空间的数组,因为,不像QVector,真正的数据不是存储在内部缓冲区,您可以创建很多空间在单指令,无论项目大小是什么(不像QVector)——因为你只是将指针添加到索引缓冲区。

For example, if you are using 32bit system (4 bytes per pointer) and you are storing 50 items in the QList, and each item is 1MB big, QVector buffer will need to be resized to 50MB, and QList's internal buffer is need to allocate only 200B of memory. This is where you need to call resize() in QVector, but in QList there is no need, since allocating small chunk of memory is not problematic, as allocating 50MB of memory.

例如,如果您正在使用32位系统(每个指针4字节),并且您正在QList中存储50个条目,并且每个条目的大小为1MB,那么QVector缓冲区将需要调整为50MB, QList的内部缓冲区只需要分配200B的内存。这就是需要在QVector中调用resize()的地方,但是在QList中没有这个必要,因为分配小块内存并没有问题,因为分配50MB内存。

However, there is a price for that which means that you sometimes you want to preffer QVector instead of QList: For single item stored in the QList, you need one additional alloc on the heap - to keep the real data of the item (data where pointer in the internal buffer is pointing to). If you want to add 10000 items larger than the pointer (because, if it can fit into pointer, it will be stored directly in the internal buffer), you will need 10000 system calls to allocate data for 10000 items on the heap. But, if you are using QVector, and you call resize, you are able to fit all the items in the single alloc call - so don't use QList if you need a lot of inserting or appending, prefer QVector for that. Of course, if you are using QList to store shared classes, there is no need for additional allocating, which again makes QList more suitable.

然而,有一个价格,这意味着你有时候要参照QVector代替QList:对于单项QList中存储,需要一个额外的分配在堆上,保持物品的真实数据(数据内部缓冲区指针是指向)。如果要添加比指针大的10000个项(因为,如果它可以装入指针,那么它将直接存储在内部缓冲区中),您将需要10000个系统调用来为堆上的10000个项分配数据。但是,如果您使用QVector,并且您调用resize,那么您就能够将所有的项都匹配到单个alloc调用中——因此,如果您需要大量插入或追加,那么不要使用QList,更喜欢使用QVector。当然,如果您正在使用QList来存储共享类,则不需要额外的分配,这也使QList更适合。

So, prefer QList for most of the cases as it is:

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

  1. Using indices to access the individual elements, accessing items will be faster that QLinkedList
  2. 使用索引访问单个元素,访问条目将比QLinkedList更快
  3. Inserting into middle of the list will only require moving of the pointers to create space, and it is faster than shifting actual QVector data around.
  4. 插入到列表的中间只需要移动指针来创建空间,这比移动实际的QVector数据要快。
  5. There is no need to manually reserve or resize space, as empty space will be moved to the end of the buffer for later use, and allocating space in the array is very fast, as the elements are very small, and it can allocate a lot of space without killing your memory space.
  6. 不需要手动储备或调整空间,空间将搬到缓冲供以后使用,和数组分配空间非常快,非常小的元素,它可以分配大量的空间没有杀死你的内存空间。

Don't use it in the following scenarios, and prefer QVector:

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

  1. If you need to ensure that your data is stored in the sequential memory locations
  2. 如果您需要确保数据存储在顺序内存位置
  3. If you are rarely inserting data at the random positions, but you are appending a lot of data at the end or beginning, which can cause a lot of unnecessary system calls, and you still need fast indexing.
  4. 如果您很少在随机位置插入数据,但是您在末尾或开头添加了大量数据,这可能导致大量不必要的系统调用,并且您仍然需要快速索引。
  5. If you are looking for (shared) replacement for simple arrays which will not grow over the time.
  6. 如果您正在寻找简单数组的(共享)替换,这些数组不会随时间增长。

And, finally, note: QList (and QVector) have reserve(int alloc) function which will cause QList's internal buffer to grow if alloc is greater than the current size of the internal buffer. However, this will not affect external size of the QList (size() will always return the exact number of elements contained in the list).

最后,注意:QList(和QVector)具有reserve(int alloc)函数,如果alloc大于内部缓冲区的当前大小,这会导致QList的内部缓冲区增加。但是,这不会影响QList的外部大小(size()总是会返回列表中包含的元素的确切数量)。

#3


0  

wasle answer is good, but it'll add the same object multiple time. Here is an utility functions that will add different object for list of smart pointers.

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());
}

For use without smart pointers, the following will add different objects to your list.

为了不使用智能指针,下面将向列表中添加不同的对象。

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());
}

Also remember that your objects must have default constructor (constructor declared in the header with arg="someValue") or else it will fail.

还要记住,对象必须具有默认构造函数(在标头中使用arg="someValue"声明的构造函数),否则它将失败。

#4


-3  

Just use something like

只使用类似

QList<Smth> myList;
// ... some operations on the list here
myList << QVector<Smth>(desiredNewSize - myList.size()).toList();

Essentially, there are these to/from Vector/List/Set() methods everywhere, which makes it trivial to resize Qt containers when necessary in a somewhat manual, but trivial and effective (I believe) way.

本质上,到处都有这些to/from向量/List/Set()方法,这使得在需要的时候以一种手工的、但简单而有效的方式(我相信)调整Qt容器的大小变得非常简单。

Another (1 or 2-liner) solution would be:

另一种(1或2-线性)解决方案是:

myList.reserve(newListSize); // note, how we have to reserve manually
std::fill_n(std::back_inserter(myList), desiredNewSize - myList.size(), Smth());

-- that's for STL-oriented folks :)

——面向stl的人:

For some background on how complex an effective QList::resize() may get, see:

要了解有效QList::resize()的复杂程度,请参见: