Утечка памяти в 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% других вопросов, предоставляя рабочий пример - за что! Вещи, которые я считаю важными для краткости:
- Включение всего необходимого модуля (ей) Qt.
- Использование
qDebug
вместоstd::cout
& al, он сохраняет включение и имеет больше стиля Qt. - Спецификаторы доступа не имеют значения, если вы используете
struct
тем не мение. - Вообще говоря, деструкторы являются либо виртуальными в общедоступном базовом классе, либо они никогда не могут быть без уступки нарезке. Так что вам не нужно это прописывать.
У меня есть пример кода, где я не следую этому, конечно. Мне нравится называть это устаревшим кодом:)
#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();
}