Speicherleck bei QT-Widget?



  • Hi,
    ich habe folgende Zeile:

    QColorDialog *k = new QColorDialog();
    

    Laut der CRT Bibliothek verursache ich damit ein Speicherleck, welches eigentlich nicht vorhanden sein drüfte da die ganzen QT-Widgets, nach meinem Wissen, beim schleißen gelöscht werden. Was CRT anscheinend nicht registriert.
    Wenn ich jetzt allerdings "k" als Member einer Klasse deklarieren und delete k in deren Destruktor schreibe, bekomme ich einen Speicherzugriffsfehler, weil versucht wird "k" nochmals zu löschen.

    Wem soll ich jetzt glauben, der CRT-Bibliothek oder meinem eigenen Halbwissen?
    Entsteht dort ein Speicherleck oder nicht, ich kann es akutell nicht beurteilen?

    Evtl. gehört das in das GUI-Forum. Da es aber für mich wie ein generelles c++ Problem wirkt hab ich es trotzdem hier gepostet. Verbessert mich wenn ich falsch liege.



  • axels. schrieb:

    Hi,

    QColorDialog *k = new QColorDialog();
    

    ...
    Wem soll ich jetzt glauben, der CRT-Bibliothek oder meinem eigenen Halbwissen?

    Ich kann etwas von meinem eigenen Halbwissen beisteuern: Soweit ich weiss ist die Speicherveraltung von Qt hierarchisch organisiert, so dass immer das Elternelement für das Löschen seiner Kinder zuständig ist.
    Deinem QColorDialog wird allerdings kein Elternelement zugewiesen (es sollte auch einen Konstruktor geben der ein parent -Irgendwas entgegennimmt), daher bist du selbst für das Löschen zuständig.
    Im Zweifellsfall kann man das Widget der Anwendung selbst zuweisen (die QApplication oder so ähnlich als parent ) oder Code im Schließen-Event ausführen, der das Widget explizit löscht.
    Eine andere Alternative ist das Widget beim Schließen einfach nur zu verstecken (das wird soweit ich weiss ohnehin gemacht) und es später wiederzuverwenden und erneut sichtbar zu machen, wenn der Dialog nochmal angezeigt werden soll.



  • Allen Objekten, die von QObject abstammen, kann bei der Konstruktion ein "parent" mit übergeben werden, der sich als Besitzer um das Zerstören kümmert.

    Im Beispiel würde sich die erzeugende Klasse (die von QObject abstammen muss), um die Zerstörung kümmern:

    QColorDialog *k = new QColorDialog(this) // this wird jetzt Eigentümer;
    

    Es geht aber auch noch etwas abgewandelt. Diese Frage habe ich mir nämlich auch bereits einmal gestellt:

    https://www.c-plusplus.net/forum/342219

    Edit: Bei Qt solltest du besser deleteLater() verwenden (falls notwendig). Das kann auch mehrfach aufgerufen werden.



  • Wenn ich nur das Schreibe

    QColorDialog* k = new QColorDialog(dynamic_cast<QWidget*>(this));
    

    entsteht dennoch ein Speicherleck.

    Deswegen hab ich es so gelöst das ich QColorDialog *k als Member definiere und im Destruktor der Klasse ein delete k aufrufe.

    temi schrieb:

    Bei Qt solltest du besser deleteLater() verwenden (falls notwendig). Das kann auch mehrfach aufgerufen werden.

    Wenn ich deleteLater() aurufe, entsteht das Problem das der Dialog erst gar nicht dargestellt wird, weil er sofort wieder geschlossen wird.

    Danke an die beiden für die Hilfe!

    Edit: Noch besser funktioniert das ganze mit smart-pointern. Dann hat man auch kein Probelm mit delete wenn der Dialog nie aufgerufen wurde.



  • axels. schrieb:

    Wenn ich nur das Schreibe

    QColorDialog* k = new QColorDialog(dynamic_cast<QWidget*>(this));
    

    entsteht dennoch ein Speicherleck.

    Ist denn dynamic_cast<QWidget*>(this) auch wirklich != nullptr?



  • und ist es überhaupt nötig?



  • axels. schrieb:

    Wenn ich nur das Schreibe

    QColorDialog* k = new QColorDialog(dynamic_cast<QWidget*>(this));
    

    entsteht dennoch ein Speicherleck.

    Edit: Noch besser funktioniert das ganze mit smart-pointern. Dann hat man auch kein Probelm mit delete wenn der Dialog nie aufgerufen wurde.

    Also ich benutze in Qt auch std::smartpointer aber dein code sieht irgendwie ein wenig merkwürdig aus.

    Wenn dein erstelltes Widget ein Parent hat dann muss es abgeräumt werden, wenn das nicht passiert stimmt irgendwas mit deinem Parent nicht oder die Art wie du es erstellt hast.

    Dein dynamic_cast sollte auch vollständig überflüssig sein. Ich habe sowas im Code an der Stelle noch nie gebraucht.



  • Ich würde raten, das die Klasse, aus der die Funktion aufgerufen wird, nicht von QWidget abgeleitet wird. Und dann geht das mit dem this Pointer natürlich nicht. Auch der Cast wird dann irgendwas zurück geben, was keinen Sinn ergibt.



  • Schlangenmensch schrieb:

    Ich würde raten, das die Klasse, aus der die Funktion aufgerufen wird, nicht von QWidget abgeleitet wird. Und dann geht das mit dem this Pointer natürlich nicht. Auch der Cast wird dann irgendwas zurück geben, was keinen Sinn ergibt.

    In diesem falle liefert dynamic_cast einen nullptr zurück wenn der cast nicht möglich ist.



  • Ich frage mich warum hier der ColorDialog überhaupt dynamisch erstellt wird. Sowas stellt doch meist ein modales Fenster dar. Somit könnte man diesen Dialog in einer Funktion als lokale Variable erzeugen. Dann gibts auch kein Problem mit dem Löschen.
    Bei QDialog hat der parent ja noch eine weitere Bedeutung. Er stellt sicher wo der Dialog gezeichnet wird. Deswegen ist der parent hier auch ein QWidget und kein QObject.
    Zum dynamic_cast. Normalerweise sollte man je wissen welchen Typ this hat. Somit sollte auch klar sein was der cast macht. Das ist alles so unnötig.



  • Der cast im Konstruktor des QColorDialogs machte wirklich keinen Sinn.

    Braunstein schrieb:

    Ich frage mich warum hier der ColorDialog überhaupt dynamisch erstellt wird. Sowas stellt doch meist ein modales Fenster dar. Somit könnte man diesen Dialog in einer Funktion als lokale Variable erzeugen. Dann gibts auch kein Problem mit dem Löschen.

    Wenn ich den Dialog als lokale Variable erstelle binkt er kurz auf und verschwindet wieder sobald die Funktion verlassen wird.

    Schlangenmensch schrieb:

    Ich würde raten, das die Klasse, aus der die Funktion aufgerufen wird, nicht von QWidget abgeleitet wird.

    Tatsächlich wird die Klasse polymorph von QTreeWidgetItem abgeleitet.



  • Braunstein schrieb:

    Sowas stellt doch meist ein modales Fenster dar.

    Tod allen modalen Dialogen!!!1einself! 😛



  • Woher weißt du, dass es ein Speicherleck ist? Dein erstes Beispiel schaut auf jeden Fall danach aus, aber woher weißt du das?
    Wenn sich irgendwelchen statischen Code Analyzer drüber beschweren, ist es noch kein Grund, denen zu glauben, die verstehen Qt nicht und können das nicht so genau analysieren. Nach dem Übergeben des Parents dürftest du kein Speicherleck mehr haben.



  • Mechanics schrieb:

    Woher weißt du, dass es ein Speicherleck ist? Dein erstes Beispiel schaut auf jeden Fall danach aus, aber woher weißt du das?
    Wenn sich irgendwelchen statischen Code Analyzer drüber beschweren, ist es noch kein Grund, denen zu glauben, die verstehen Qt nicht und können das nicht so genau analysieren. Nach dem Übergeben des Parents dürftest du kein Speicherleck mehr haben.

    Das ist ja gerade die Frage die sich mir stellt. Soll ich meinem Wissen über QT trauen oder dem was mir die CRT-Bibliothek meldet.



  • Setz doch einfach einen Breakpoint im Destruktor, und schau ob das Ding wirklich gelöscht wird.



  • axels. schrieb:

    Braunstein schrieb:

    Ich frage mich warum hier der ColorDialog überhaupt dynamisch erstellt wird. Sowas stellt doch meist ein modales Fenster dar. Somit könnte man diesen Dialog in einer Funktion als lokale Variable erzeugen. Dann gibts auch kein Problem mit dem Löschen.

    Wenn ich den Dialog als lokale Variable erstelle binkt er kurz auf und verschwindet wieder sobald die Funktion verlassen wird.

    Wenn der Dialog nur kurz aufblinkt, dann rufst du ihn falsch auf. Es kommt jetzt darauf an was der Dialog machen soll.

    axels. schrieb:

    Schlangenmensch schrieb:

    Ich würde raten, das die Klasse, aus der die Funktion aufgerufen wird, nicht von QWidget abgeleitet wird.

    Tatsächlich wird die Klasse polymorph von QTreeWidgetItem abgeleitet.

    QTreeWidgetItem ist ungeeignet als parent für den Dialog da es nicht von QWidget, ja noch nicht mal von QObject abgeleitet ist. Du könntest aber als Parent den parent von deiner QWidgetItem-Klasse nehmen. Das sollte ja ein QTreeWidget sein und ist somit verwendbar.

    Das Ganze gehört aber langsam ins Qt-Forum.



  • Ok, jetzt abschließend eine richtige Lösung:

    QColor color = QColorDialog::getColor();
    

    Kommt ganz ohne dynamisches Objekt aus.

    Warum hab ich das von Anfang an nicht so gemacht?
    Weil ich die Möglichkeit einfach nicht kannte.


Anmelden zum Antworten