Fuite de mémoire dans Qt5? Comment faire pour supprimer QMimeData?

Je viens de fournir une réponse à cette question et souhaitais fournir un exemple de travail lorsque j’ai remarqué que l’instance QMimeData nouvellement créée, renvoyée par QListModel::mimeData() , ne sera supprimée que lorsque l’application sera terminée.

Il ne s’agit donc pas d’une véritable fuite de mémoire puisque Qt gère toutes les instances de QMimeData à l’arrêt, mais il vous suffit de faire glisser et de déposer suffisamment de temps et de placer le bon contenu dans vos données mime pour que la mémoire soit saturée.

Ai-je manqué quelque chose? Existe-t-il un moyen d’indiquer à Qt de supprimer les instances de QMimeData dès qu’elles ne sont plus nécessaires?

Notez s’il vous plaît:

Je sais que chaque instance de QMimeData est automatiquement supprimée par Qt à la fin du programme. Mon problème ici n’est pas une fuite de mémoire réelle telle que rapscope par valgrind ou cppcheck mais il semble que les instances multiples et potentiellement très volumineuses de QMimeData ne soient pas nettoyées au moment de l’exécution, ce qui augmente également la consommation de mémoire.

Exemple de code:

 #include  #include  struct TrackedMimeData : public QMimeData { TrackedMimeData(const QSsortingng & 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) const override { return new TrackedMimeData("hello"); } }; int main(int argsc, char *argsv[]) { QApplication application(argsc, argsv); MyListWidget gui; gui.show(); return application.exec(); } 

Exemple de sortie ressemble à ceci:

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

Les destructeurs sont appelés avant la fermeture de l’application uniquement lorsque la suppression est acceptée.

Btw. Je suis sur un Qt 5.6 @ 1fcdb6cafcf maison – sur un ordinateur et sur 5.6.0-19.fc23 Fedora 23 précompilé sur un autre. Donc, je doute que ce soit juste un état de développement temporaire.

Il y a une fuite de mémoire uniquement si vous oubliez de supprimer le pointeur renvoyé par mimeData() . Vous devez gérer la propriété comme avec n’importe quel pointeur.

Par exemple, si vous transmettez le pointeur renvoyé par mimeData() à un object QDrag aide de setMimeData() , il en prendra possession et se chargera de le supprimer à la fin de l’opération de glissement. Il n’y a pas de fuite de mémoire dans ce cas.

Voir: http://doc.qt.io/qt-5/qdrag.html#setMimeData

Cela devrait arriver, si ce n’est pas le cas, alors c’est un bogue – vous ne pouvez rien y faire, à part le signaler s’il n’a pas encore été signalé.

Je ne peux pas le reproduire sur OS X avec Qt 5.6. Il peut s’agir d’une plate-forme spécifique ou d’un bogue déjà corrigé dans une ancienne version de Qt. Dès que je relâche le bouton de la souris à la fin du glissement, les données mime sont supprimées. Lorsque le destructeur s’exécute, la stack d’appels appelle le destructeur QDrag partir de la boucle d’événements via deleteLater quelque part. J’ai utilisé votre code mot à mot.

Encadré: Cela pourrait être légèrement plus minimal si vous le vouliez aussi court que possible. Voici ce que j’ai, bien que je convienne que c’est principalement couper les cheveux en deux. Votre question bat 99% des autres questions en fournissant un exemple concret – un grand bravo pour cela ! Les choses qui, à mon avis, importent pour la brièveté sont:

  1. Inclusion de l’intégralité du ou des modules Qt nécessaires.
  2. Utilisation de qDebug au lieu de std::cout & al, cela enregistre un include et est plus du style Qt.
  3. Les spécificateurs d’access n’ont pas d’importance si vous utilisez de toute façon struct .
  4. En règle générale, les destructeurs sont virtuels dans la classe de base publique ou ne peuvent jamais l’être sans succomber au découpage en tranches. Donc, vous n’avez pas à préciser cela.

J’ai un exemple de code où je ne suis pas cela, bien sûr. J’aime l’appeler le code hérité 🙂

 #include  struct TrackedMimeData : QMimeData { TrackedMimeData(const QSsortingng & text) { qDebug() << this; setText(text); } ~TrackedMimeData() { qDebug() << "~" << this; } }; struct MyListWidget : QListWidget { MyListWidget() { setDragEnabled(true); addItem("item1"); addItem("item2"); } QMimeData * mimeData(const QList) const override { return new TrackedMimeData("hello"); } }; int main(int argsc, char *argsv[]) { QApplication application(argsc, argsv); MyListWidget gui; gui.show(); return application.exec(); }