#c #qt #qlist
#c #qt #qlist
Вопрос:
Допустим, у меня есть этот класс:
class Bear
{
public:
Bear ();
Bear (Bear amp;other);
// ... methods
private:
BearInfo* m_pInfo;
};
Могу ли я хранить Bear
объекты в коллекции QList<Bear>
по значению? Согласно документации:
Внутренне
QList<T>
представлено в виде массива указателей на элементы типаT
. ЕслиT
это сам тип указателя или базовый тип, который не больше указателя, или еслиT
это один из совместно используемых классов Qt, тоQList<T>
элементы сохраняются непосредственно в массиве указателей.
Хотя мой класс состоит просто из указателя, он не является ни типом указателя, ни базовым типом, поэтому мне кажется, что QList
будет хранить указатели ( Bear*
), а это не то, что я хочу. И поскольку BearInfo
структура должна быть изменяемой, я не могу вывести Bear
из QSharedDataPointer
.
Есть предложения, как я могу включить сохранение этого класса по значению в коллекциях Qt?
Комментарии:
1. Что вообще означает «базовый тип» в этом контексте? Модуль?
2. Я предполагаю, что int, char, long и т.д.
3. Джен, ты права насчет базового типа. если вы не хотите использовать amp; ваши классы, используйте контейнер stl, который может эффективно соответствовать размеру полной структуры данных в оперативной памяти. Qt любит указатели 😉
4. Ну, в поиске правильного ответа, предположение заходит так далеко. ;-] Если это означает, что его можно тривиально копировать, то ваш класс должен соответствовать критериям » базовый тип, размер которого не больше указателя «; если это означает POD, то ваш класс не соответствует. Итак, мне кажется, что ответ на мой вопрос также является ответом на ваш — документы Qt когда-либо явно определяли «базовый тип»?
5. Хороший момент. В документации QML термин » базовый тип » используется для обозначения любого из примитивов, а также некоторых предоставляемых Qt типов, таких как QString, QDate, QFont и т.д.
Ответ №1:
Используйте QVector, в документации Qt указано это:
QList, QLinkedList и QVarLengthArray предоставляют аналогичную функциональность. Вот обзор:
- Для большинства целей QList является подходящим классом для использования. Такие операции, как prepend() и insert(), обычно выполняются быстрее, чем с QVector, из-за способа, которым QList хранит свои элементы в памяти (подробности см. в разделе Алгоритмическая сложность), а его API на основе индекса удобнее, чем API на основе итератора qlink.LinkedList. Он также расширяется до меньшего количества кода в вашем исполняемом файле.
- Если вам нужен реальный связанный список с гарантиями постоянных временных вставок в середину списка и итераторов к элементам, а не к индексам, используйте QLinkedList.
- Если вы хотите, чтобы элементы занимали смежные позиции в памяти, или если ваши элементы больше указателя, и вы хотите избежать накладных расходов на выделение их в куче по отдельности во время вставки, тогда используйте QVector.
- Если вам нужен низкоуровневый массив переменного размера, QVarLengthArray может быть достаточным.
Ответ №2:
просто используйте контейнер stl, он доступен везде, даже в QT.
это то, что я делаю. 🙂
Комментарии:
1. Думал об этом, но мне нравятся классы Qt за их более чистый синтаксис и лучшие характеристики производительности.
2. Да, я знаю, что синтаксис Qt очень элегантный. Но они сложны, когда дело доходит до выделения, в то время как контейнер stl — нет.
3. @ildjarn: В Qt есть некоторые оптимизации, касающиеся мелкого / глубокого копирования и вставки списков… но, к сожалению, нет cite 🙁
Ответ №3:
Могу ли я хранить объекты Bear в
QList<Bear>
по значению?
Нет. Ваша цитата из документации была правильной: внутри QList<T>
хранятся указатели на элементы типа T
.
Вместо этого используйте QVector
, который хранит объекты по значению типа, большего, чем указатель (это его назначение).
Аналогичная проблема с элементами в QList<>
— это проблемы с удержанием с помощью QVariant
, который содержит любой примитивный тип или некоторые другие небольшие типы (например QDate
). Таким образом, вы получаете семантику значения в QVariant
только в том случае, если ваше значение вписывается в примитив или указатель.
Полное сдерживание было бы достигнуто, если бы у вас был контейнер объектов, таких как экземпляры QPointer
или QSharedPointer
, которые логически совместно используют и отслеживают ссылки на объекты (с подсчетом ссылок) и т.д.
В отличие от STL (с семантикой значений), Qt опирается на контейнеры «указателей на элементы» из-за проблем, когда эти элементы полиморфны (разные размеры в производных классах). (Это довольно распространено в объектно-ориентированных системах, поэтому Qt по умолчанию использует семантику указателя.)
Например, в Qt QList<Bear>
это нормально (реализовано как контейнер указателей на Bear
экземпляры), но std::list<Bear>
было бы проблематично, если бы все экземпляры Bear не были одинакового размера (например, if KodiakBear
и BlackBear
производные от Bear
, и вы добавили эти производные экземпляры в std::list<Bear>
класс). В этом случае производное состояние будет «удалено» с помощью семантики значения.