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