Управление данными QAbstractItemModel в QSharedPointers

В c++ Qt мне нравится управлять памятью кучи с помощью QSharedPointers, но можно/нужно также использовать их для управления данными в QAbstractItemModel?

Например, можно иметь список QStrings QList<QSharedPointer<QString> > queue.

Проблема в том, что при реализации QSharedAbstractItemModel, как и QAbstractListModel, вам нужно иметь дело с необработанными указателями. Например, метод index возвращает QModelIndex, который принимает пустой указатель в конструкторе, указывающий на одну из этих строк QString в куче. Как только вы создаете этот объект, вы работаете как с управляемой, так и с неуправляемой памятью кучи.

Поэтому, если я сохраняю выбранный элемент где-то в указателе, а затем очищаю свою модель, данные для этого указателя удаляются.

Так как же поступить с объектами памяти кучи, которые вы хотите поместить в QAbstractItemModel

Я использую qt 5.1.


person Halfgaar    schedule 21.01.2015    source источник
comment
Халфгаар, это не ответ на твой вопрос, но почему бы просто не взять QList<QString>? Qt использует неявный общий доступ, поэтому он позаботится о совместном использовании данных. для тебя   -  person Innocent Bystander    schedule 21.01.2015
comment
Я знаю о неявном совместном использовании. Это потому, что я работаю со списками своих собственных объектов, и мне нужно сохранить сигналы и соединения слотов.   -  person Halfgaar    schedule 21.01.2015


Ответы (1)


С точки зрения управления памятью, это зависит от вашего выбора.

QAbstractListModel требует, чтобы вы написали функцию данных, которая возвращает QVariant. Откуда вы создаете этот вариант, на самом деле не имеет значения.

Сам QVariant — это новая структура, она никак не влияет на ваши данные.

Возьмите этот пример:

 QVariant MyListImplementation::data(const QModelIndex& index, int role) const 
 {
     // QSharedPointer<QList<QString>> sharedMessageQueue
     // QList<QString>* pMessageQueue
     if (useSharedPointers)
     {
         return QVariant::fromValue(sharedMessageQueue->at(index.row()));
     } else {
         return QVariant::fromValue(pMessageQueue->at(index.row));
     }
 }

Таким образом, вы можете увидеть две вещи:

  1. Вы создаете QVariant из значения, и вы передаете этот QVariant по значению, то есть QVariant имеет свою собственную память, а управление памятью передается объекту, который запрашивает данные (Вы не можете вернуть общий указатель QVariant, так как вы необходимо реализовать эту конкретную сигнатуру метода)

  2. Реализация не зависит от политики памяти, которую вы используете для списка MessageQueue.

Если вы используете общий указатель для данных в своем списке, вам не нужно беспокоиться об освобождении списка в деструкторе, если вам не нужно удалять список в деструкторе класса.

Если вы хотите обсудить, хорошо ли использовать QSharedPointers внутри реализации QAbstarctListModel, вы получите те же ответы, что и на вопрос Полезно ли это и каковы компромиссы при использовании общих указателей внутри проекта? .

РЕДАКТИРОВАТЬ :

По поводу вашего комментария:

Вы обеспокоены тем, что происходит, когда createIndex используется для генерации QModelIndex и использования внутреннего необработанного указателя QModelIndex.

В документации QT:

Примечание. Модельные индексы следует использовать немедленно, а затем отбрасывать. Не следует полагаться на то, что индексы останутся действительными после вызова функций модели, которые изменяют структуру модели или удаляют элементы. Если вам нужно сохранить индекс модели с течением времени, используйте QPersistentModelIndex.

...

QModelIndex QAbstractItemModel::createIndex (строка int, столбец int, void * ptr = 0) const [защищено]

Создает индекс модели для данной строки и столбца с внутренним указателем ptr.

При использовании QSortFilterProxyModel ее индексы имеют собственный внутренний указатель. Не рекомендуется обращаться к этому внутреннему указателю за пределами модели. Вместо этого используйте функцию data().

Насколько я понимаю, QModelIndex - это просто временная структура, используемая для извлечения данных из модели. Думайте об этом как об эквиваленте временной таблицы при использовании базы данных: вы знаете, что получите доступ к определенной информации из таблицы (не ко всей информации) для нескольких операций в определенной части вашей программы, но вы не хотите запрашивать базу данных для каждого из них, вы просто получаете их как часть в одном запросе, используете их в соответствии со своими потребностями, а затем отбрасываете.

В документации QT упоминается практический пример того, как QModelIndex может использоваться для доступа к данным вне модели (поэтому вместо использования model.data вы используете QModelIndex.data), но это исключение, поскольку данные существуют в памяти в том же порядке. были введены, их индексы изменились (из-за сортировки/фильтрации).

С точки зрения управления памятью, QModelIndex хранит внутри себя слабые указатели, поэтому действительно, если вы удалите данные, ваш QModelIndex будет указывать на недопустимое местоположение. Но с точки зрения сбрасывания памяти вам не о чем беспокоиться, поскольку она ничего не выделяет динамически (слабые указатели :)).

Где вам действительно нужно беспокоиться, так это в многопоточных средах, где вы получаете QModelIndex в потоке A , но до того, как поток A отбрасывает этот QModelIndex, ваш поток B удаляет модель. Однако, если у вас есть это, у вас проблема с синхронизацией.

Вы можете обойти всю эту синхронизацию, создав глубокую копию QModelIndex (это означает, что вы скопируете его внутренний указатель, а затем сделаете его общим указателем), но я бы использовал синхронизацию, если это возможно.

person MichaelCMS    schedule 21.01.2015
comment
Мой вопрос больше связан с наличием QList<QSharedPointer<QString> > queue против QList<QString*> queue. И метод данных не проблема. Меня больше беспокоит создание QModelIndex из queue.at, а затем передача необработанного указателя. - person Halfgaar; 21.01.2015