Я просто заметил, что QList
не имеет resize
метод, в то время как QVector
Например, есть один. Почему это? И есть ли эквивалентная функция?
Я думаю, что причина в том, что 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());
}
Ну, это более общий ответ, но я надеюсь, что вы увидите, сравнив 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
для большинства случаев, как это:
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-линейное) решение будет:
myList.reserve(newListSize); // note, how we have to reserve manually
std::fill_n(std::back_inserter(myList), desiredNewSize - myList.size(), Smth());
— это для STL-ориентированных людей 🙂
Для некоторого фона о том, насколько сложный эффективный QList::resize()
может получить, посмотри: