Утечка памяти в Qt5? Как удалить QMimeData?

Я просто дал ответ на этот вопрос и хотел привести рабочий пример, когда заметил, что недавно созданный QMimeData экземпляр возвращен QListModel::mimeData() не будет удален, пока приложение не будет прекращено.

Так что это не настоящая утечка памяти, так как Qt обрабатывает все QMimeData экземпляры при отключении, но вам нужно только перетащить и оставить достаточно долго и поместить нужный контент в ваши данные MIME, чтобы позволить памяти заполниться.

Я что-то пропустил? Есть ли способ сказать Qt, чтобы удалить QMimeData экземпляры, как только они больше не нужны?

Пожалуйста, обратите внимание:

Я знаю, что каждый случай QMimeData удаляется Qt автоматически по завершении программы. Моя проблема здесь не в реальной утечке памяти, как сообщили valgrind или же cppcheck но это выглядит как кратное и потенциально очень большое QMimeData экземпляры не очищаются во время выполнения, что также увеличивает потребление памяти.

Пример кода:

#include <QtWidgets>
#include <iostream>

struct TrackedMimeData : public QMimeData {
   TrackedMimeData(const QString & text) {
      std::cout << this << std::endl;
      setText(text);
   }
   ~TrackedMimeData() {
       std::cout << "~" << this << std::endl;
   }
};

struct MyListWidget : QListWidget {
   MyListWidget() {
      setDragEnabled(true);
      addItem("item1");
      addItem("item2");
   }
   QMimeData * mimeData(const QList<QListWidgetItem *>) const override {
      return new TrackedMimeData("hello");
   }
};

int main(int argsc, char *argsv[]) {
   QApplication application(argsc, argsv);
   MyListWidget gui;
   gui.show();
   return application.exec();
}

Пример вывода выглядит так:

0xa58750
0xa4e0f0
~0xa4e0f0
0xa3c6c0
~0xa3c6c0
0xa51880
0xa5ecd0
0xa31f50
0xa57db0
0xa5afc0
~0xa5afc0
0xa5aa70
~0xa5aa70
------ CLOSE WINDOW
~0xa58750
~0xa51880
~0xa5ecd0
~0xa31f50
~0xa57db0

Деструкторы вызываются перед закрытием приложения только тогда, когда отбрасывается прием.

Btw. Я работаю на доморощенном Qt 5.6 @ 1fcdb6cafcf - на одном компьютере и на 5.6.0-19.fc23 Fedora 23, предварительно скомпилированном на другом. Поэтому я сомневаюсь, что это просто временное состояние развития.

2 ответа

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

Например, если вы передаете mimeData() возвращенный указатель на QDrag использование объекта setMimeData()он будет владеть им и позаботится об его удалении в конце операции перетаскивания. В этом случае утечки памяти нет.

Смотрите: http://doc.qt.io/qt-5/qdrag.html

Это должно происходить, если это не так, то это ошибка - вы ничего не можете с этим поделать, кроме как сообщить об этом, если об этом еще не сообщалось.

Я не могу воспроизвести его на OS X с Qt 5.6. Это может быть для конкретной платформы или уже исправленной ошибки в старой версии Qt. Как только я отпускаю кнопку мыши в конце перетаскивания, данные MIME удаляются. Стек вызовов при выполнении деструктора имеет QDrag деструктор вызывается из цикла событий через deleteLater где-то. Я использовал ваш код дословно.

Боковая панель: ее можно сделать чуть более минималистичной, если вы действительно хотите, чтобы она была максимально короткой. Вот что я получил, хотя я согласен, что это в основном расщепление волос. Ваш вопрос превосходит 99% других вопросов, предоставляя рабочий пример - за что! Вещи, которые я считаю важными для краткости:

  1. Включение всего необходимого модуля (ей) Qt.
  2. Использование qDebug вместо std::cout & al, он сохраняет включение и имеет больше стиля Qt.
  3. Спецификаторы доступа не имеют значения, если вы используете struct тем не мение.
  4. Вообще говоря, деструкторы являются либо виртуальными в общедоступном базовом классе, либо они никогда не могут быть без уступки нарезке. Так что вам не нужно это прописывать.

У меня есть пример кода, где я не следую этому, конечно. Мне нравится называть это устаревшим кодом:)

#include <QtWidgets>

struct TrackedMimeData : QMimeData {
   TrackedMimeData(const QString & text) {
      qDebug() << this;
      setText(text);
   }
   ~TrackedMimeData() {
      qDebug() << "~" << this;
   }
};

struct MyListWidget : QListWidget {
   MyListWidget() {
      setDragEnabled(true);
      addItem("item1");
      addItem("item2");
   }
   QMimeData * mimeData(const QList<QListWidgetItem *>) const override {
      return new TrackedMimeData("hello");
   }
};

int main(int argsc, char *argsv[]) {
   QApplication application(argsc, argsv);
   MyListWidget gui;
   gui.show();
   return application.exec();
}
Другие вопросы по тегам