Почему QList не имеет метода resize ()?

Я только что заметил, что QList нет resize метод, в то время как QVector, например, был один. Почему так? И есть ли эквивалентная функция?

4 ответов


Я думаю, причина в том, что 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());
}

Ну, это более общий ответ, но я надеюсь, что вы увидите, comparising QList и QVector почему нет необходимости вручную расширять контейнер.

QList использует внутренний буфер для сохранения указателей на элементы (или, если элемент меньше размера указателя, или элемент является одним из общие классы - elements), а реальные данные будут храниться в куче.

во время, извлекать данные не уменьшит внутренний буфер (пустое пространство будет заполнено сдвигом левых или правых элементов, оставляя место в начале и конце для последующих вставок).

добавление элементов, таких как QVector создаст дополнительное новое пространство в конце массива, и так как, в отличие от QVector, реальные данные не хранятся во внутреннем буфере, вы можете создать много пространства в одной инструкции, независимо от того, какой размер элемента (в отличие от QVector) - потому что вы просто добавляете указатели в буфер индексирования.

например, если вы используете 32-битную систему (4 байта на указатель) и храните 50 элементов в QList, и каждый деталь 1Mb большое,QVector буфер должен быть изменен до 50 МБ, и QListвнутренний буфер должен выделять только 200B памяти. Здесь вам нужно позвонить resize() на QVector, но в QList нет необходимости, так как выделение небольшого куска памяти не является проблематичным, так как выделение 50 МБ памяти.

однако, существует цена за то, что означает, что вы иногда хотите preffer QVector вместо QList: для одного элемента, хранящегося в QList, вам нужен один дополнительный аллок в куче-чтобы сохранить реальные данные элемента (данные, на которые указывает указатель во внутреннем буфере). Если вы хотите добавить 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() всегда возвращает точное количество элементов, содержащихся в списке).


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/List/Set() методы везде, что делает тривиальным изменение размера контейнеров Qt при необходимости в несколько ручном, но тривиальном и эффективном (я считаю) способе.

другое решение (1 или 2-liner) будет:

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

-- это для STL-ориентированных людей:)

для некоторого фона о том, насколько сложный эффективный QList::resize() может вам, см.: