Qt: сохранение пользовательского объекта в коллекции по значению

#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> класс). В этом случае производное состояние будет «удалено» с помощью семантики значения.