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

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

13

Решение

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

Другие решения

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

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

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

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

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

Тем не менее, есть цена за это, что означает, что вы иногда хотите преференции QVector вместо QList: Для одного элемента, хранящегося в QListвам нужно еще одно выделение в куче — чтобы сохранить реальные данные элемента (данные, на которые указывает указатель во внутреннем буфере). Если вы хотите добавить 10000 элементов больше, чем указатель (потому что, если он может поместиться в указатель, он будет сохранен непосредственно во внутреннем буфере), вам потребуется 10000 системных вызовов, чтобы выделить данные для 10000 элементов в куче. Но если вы используете QVectorи ты звонишь resizeвы можете разместить все элементы в одном вызове alloc — так что не используйте QList если вам нужно много вставлять или добавлять, предпочитайте QVector для этого. Конечно, если вы используете QList для хранения разделяемых классов нет необходимости в дополнительном распределении, что снова делает QList более подходящий.

Итак, предпочитаю QList для большинства случаев, как это:

  1. Используя индексы для доступа к отдельным элементам, доступ к элементам будет быстрее, чем QLinkedList
  2. Вставка в середину списка потребует только перемещения указателей для создания пробела, и это быстрее, чем смещение фактического QVector данные вокруг.
  3. Нет необходимости вручную резервировать или изменять размер пространства, так как пустое пространство будет перемещено в конец буфера для последующего использования, и выделение пространства в массиве происходит очень быстро, поскольку элементы очень малы, и это может выделить много пространства, не убивая пространство памяти.

Не используйте его в следующих сценариях и предпочитайте QVector:

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

И, наконец, обратите внимание: QList (а также QVector) иметь reserve(int alloc) функция, которая вызовет QListвнутренний буфер для роста, если alloc больше, чем текущий размер внутреннего буфера. Однако это не повлияет внешний размер из QList (size() всегда будет возвращать точное количество элементов, содержащихся в списке).

10

Ответ 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»), иначе он потерпит неудачу.

0

Просто используйте что-то вроде

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

По сути, есть эти to/from Vector/List/Set() методы везде, что делает тривиальным изменение размера контейнеров Qt, когда это необходимо, несколько ручным, но тривиальным и эффективным (я считаю) способом.

Другое (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() может получить, посмотри:

-3
По вопросам рекламы [email protected]