Qt рекламирует QList
как "мастера на все руки", но другая половина этого высказывания - "мастер ни в чем". Я бы сказал, что QList
является хорошим кандидатом, если вы планируете добавлять к обоим концам списка, и они не больше указателя, поскольку QList
резервирует место до и после. Вот и все, я имею в виду веские причины для использования QList
.
QList
будет автоматически сохранять "большие" объекты в качестве указателя и выделять объекты в куче, что можно считать хорошей вещью, если вы ребенок, который не знает, как объявить QVector<T*>
и использовать динамическое размещение. Это не обязательно хорошо, и в некоторых случаях это только увеличит использование памяти и добавит дополнительную косвенность. IMO, всегда полезно четко указать, что вы хотите, будь то указатели или экземпляры. Даже если вам нужно выделение кучи, всегда лучше выделить ее самостоятельно и просто добавить указатель в список, чем создавать объект один раз, а затем копировать его в куче.
Qt вернет вам QList
во многих местах, где это связано с накладными расходами, например, при получении дочерних элементов QObject
или при поиске дочерних элементов. В этом случае нет смысла использовать контейнер, который выделяет место перед первым элементом, поскольку это список объектов, которые уже есть, а не то, к чему вы, вероятно, не будете добавляться. Мне также не очень нравится отсутствие метода resize()
.
Представьте ситуацию, когда у вас есть объект размером 9 байт и выравниванием по байтам в 64-битной системе. Это «слишком много» для QList
, поэтому вместо этого он будет использовать 8-байтовый указатель + накладные расходы ЦП для медленного выделения кучи + накладные расходы памяти для выделения кучи. Он будет использовать в два раза больше памяти, а с дополнительным косвенным доступом он вряд ли обеспечит преимущества в производительности, как рекламируется.
Что касается того, почему QVector
не может внезапно стать контейнером «по умолчанию» — вы не меняете лошадей в середине гонки — это устаревшая вещь, Qt — такой старый фреймворк, и хотя многие вещи устарели, внесение изменений в широко используемые значения по умолчанию не всегда возможны, не без нарушения большого количества кода или создания нежелательного поведения. Хорошо это или плохо, но QList
, скорее всего, останется значением по умолчанию на протяжении всей Qt 5, а также, вероятно, и в следующем крупном выпуске. По той же причине Qt будет продолжать использовать «тупые» указатели в течение многих лет после того, как умные указатели стали обязательными, и все плачут о том, насколько плохи простые указатели и что их никогда не следует использовать.
При этом никто не заставляет вас использовать QList
в своем дизайне. Нет причин, по которым QVector
не должен быть вашим контейнером по умолчанию. Я сам нигде не использую QList
, а в функциях Qt, которые возвращают QList
, я просто использую их как временные для перемещения материала в QVector
.
Кроме того, и это только мое личное мнение, но я нахожу много дизайнерских решений в Qt, которые не обязательно имеют смысл, будь то производительность или эффективность использования памяти или простота использования, и в целом существует множество фреймворков. и языки, которым нравится продвигать свои способы ведения дел не потому, что это лучший способ сделать это, а потому, что это их способ делать это.
Последний, но тем не менее важный:
Для большинства целей подходит класс QList.
Это действительно сводится к тому, как вы это понимаете. ИМО в этом контексте «правильный» означает не «лучший» или «оптимальный», а «достаточно хороший», как в «подойдет, даже если не лучший». Особенно, если вы ничего не знаете о разных классах контейнеров и о том, как они работают.
Для большинства целей подойдет QList.
Подводя итог:
QList
PRO
- вы собираетесь добавлять объекты размером не больше указателя, так как он оставляет некоторое место впереди
- вы намерены вставить в середину списка объекты (существенно) больше указателя (и я здесь великодушен, так как вы можете легко использовать
QVector
с явными указателями для достижения того же и дешевле - без лишней копии), так как при изменении размера список, никакие объекты не будут перемещены, только указатели
QList
минусы
- не имеет метода
resize()
, reserve()
является тонкой ловушкой, так как он не увеличит действительный размер списка, даже если доступ к индексу работает, он попадает в категорию UB, также вы не сможете перебрать этот список
- делает дополнительную копию и выделяет кучу, когда объект больше указателя, что также может быть проблемой, если идентификация объекта имеет значение
- использует дополнительную косвенность для доступа к объектам, большим, чем указатель
- имеет накладные расходы процессорного времени и памяти из-за последних двух, а также менее удобен для кеша
- поставляется с дополнительными накладными расходами при использовании в качестве возвращаемого значения «поиск», поскольку вы вряд ли будете добавлять или даже добавлять к этому
- имеет смысл только в том случае, если доступ к индексу является обязательным, для оптимальной производительности добавления и вставки связный список может быть лучшим вариантом.
CON немного перевешивает PRO, а это означает, что, хотя в «случайном» использовании QList
может быть приемлемым, вы определенно не хотите использовать его в ситуациях, когда время процессора и/или использование памяти являются критическим фактором. В общем, QList
лучше всего подходит для ленивого и небрежного использования, когда вы не хотите рассматривать оптимальный контейнер для хранения для варианта использования, которым обычно будет QVector<T>
, QVector<T*>
или QLinkedList
(и я исключаю " STL», поскольку мы говорим здесь о Qt, контейнеры Qt столь же переносимы, иногда быстрее и, безусловно, проще и чище в использовании, тогда как контейнеры std
излишне многословны).
person
dtech
schedule
26.11.2015