Programmieren mit qt: new vs. delete

R

rikola

Foren Gott
Ich gucke mir grade ein paar Beispiele zu Qt4.2 an, zum Beispiel dieses hier. Dabei faellt auf, dass sehr selten, manchmal nie, der Speicher, der mit 'new' angefordert wurde, wieder freigegeben wird. Dieser thread behauptet zwar, dass man sich nicht darum kuemmern muesse, da die Elternwidgets sich um das Loeschen der Kinder kuemmern (wobei ich selbst das bezweifle, da beim Freigeben eines Zeigers ja nicht der Speicherbereich freigegeben wird, auf den er zeigt, wenn man nicht delete benutzt!). Allerdings sehe ich z.B. in obigem Beispiel nicht, dass die Widgets als Kinder erzeugt werden (parent=0 als default), ausserdem gibt es nicht mal ein einziges delete.

Muss man sich unter Qt nicht darum kuemmern, weil man davon ausgeht, dass nicht so viele Fenster erzeugt werden/ geloescht werden, dass man in den Bereich von Speicherproblemen kommen koennte, ist die Programmiertechnik unter den Qt-Tutorials nicht die optimalste, oder uebersehe ich etwas Entscheidendes?
 
Ich sag's mal kurz:
malloc&free, new&delete sind USERSPACE.
Sobald dein Programm beendet wird räumt der Kernel eh alles auf.

Wenn du z.B. ein free oder ein delete machst, wird nicht zwingend wieder Speicher an den Kernel zurückgegeben.
Sieh dir dazu mal man sbrk an.

Man kann es auch so sagen:
Wenn du weißt, dass dieses Programm nicht lange läuft, kannste auf's delete verzichten. Ist halt nur nicht sauber.
 
boa das wäre der inbegriff des schlechten proggens und kann speicherlecks erzeugen das ist dir klar! ich habe zwar lange nicht mehr programmiert (studium der biologie fordert immens viel zeit) aber ich weiß das zum. bei qt3 ein fehlendes delete einen spez. einfluss nahm.... ich hatte auch mal bei qtforum.de was drübergelesen... hmm denkedenke... mir fällt nichts mehr ein...

probiers einfach mal aus.. ob dein programm wirkl einen destr. erzeugt wenn dus beendest. und vergiss nicht. das du für alle non-widgets unbedingt ein delete anhängen solltest.

generell ist es guter stil ein eigenen destruktor zu erzeugen bzw. an best. stellen das nicht. benötigte widget zu zerstören um das programm evtl. schon zur laufzeit schlanker zu machen.

und dann sei noch gesagt das du nicht weißt wohin du das prog. portieren willst. nicht jedes os räumt auf!
 
*hust* Ich _weiß_ dass dies schlechter Stil ist.
Und alles was nicht aufräumt ist für mich kein OS.
 
Um wieder zum eigentlichen Thema zurück zu kommen. Alle Widgets die du in dem Beispiel mit new erzeugst sind "Teil" des Hauptfensters bzw. haben am Ende das Hauptfenster als Eltern-Widget. Wenn das Hauptfenster gelöscht wird, werden von Qt automatisch auch alle Kinder sauber abgeräumt. Da alle Widgets als Teil des Hauptfensters so lange Leben wie das Hauptfenster selber brauchst du in diesem Beispiel also nie ein delete.

Allerdings sehe ich z.B. in obigem Beispiel nicht, dass die Widgets als Kinder erzeugt werden (parent=0 als default), ausserdem gibt es nicht mal ein einziges delete.

Wenn Widgets in einem anderen Widget angeordnet werden, wird automatisch eine Eltern<->Kind Verbindung erzuegt. Du kannst dir das auch als einen Baum vorstellen, die Wurzel ist das Fenster und darunter sind alle Widgets die da in welcher Form auch immer reingeschachtelt werden.
Wenn das Hauptfenster beendet wird erzeugt Qt automatisch ein delete Signal das dann durch den ganzen "Baum" propagiert wird und somit alles sauber abräumt.
 
Zuletzt bearbeitet:
Danke, pinky, das war eine sehr verstaendliche Erklaerung. Wenn Qt die delete-Kaskade selber automatisch vornimmt, bedeutet das aber auch, dass es sogar gefaehrlich ist, selber ein Widget, dass man mit 'new' angelegt hat, mit delete wieder freizugeben, da es sonst zu einem 2fachen delete kommen kann?

Ist das irgendwo dokumentiert? Ich gebe zu, dass ich nicht die ganze Qt-Dokumentation durchgelesen habe, v.a. die einleitenden Kapitel nicht...

@hehejo
Ich muss mich der Kritik von slash-ex anschliessen, ob man nun auf einem sauberen OS arbeitet oder nicht: Wenn ich einen Rechner ein Jahr oder mehr laufen habe, auf dem z.B. KDE Kindprozesse oeffnet, die aehnlich lange laufen, wuerde es sehr schnell zu einem vollen Speicher kommen, wenn erst bei beenden des Hauptprogrammes der Speicher wieder freigegeben wuerde. Jedes 'save as' Fenster vom konqueror oeffnet mit Sicherheit so einige Widgets, die dann alle im Speicher rumhaengen wuerden,solange Konqueror noch laeuft. Nach Erklaerung von pinky wird das jedoch von Qt abgefangen.
 
nicht von qt an sich. die widgets sind alle als "ordentliche" klassen mit nem destruktor geschrieben. bei beenden wirde das widget also delete-d.

wenn man nun mit vererbt, bekommt die tochterklasse den destruktor mit in die wiege. mehr ist das nicht.

wenn das widget also die ganze zeit benötigt wird isses egal. muss es evtl. neu erzeugt werden bleiben mit new jedesmal allokierter speicher zurück. das nutze ich manchmal um zeiger auf objekte zu erzeugen um zw. klassen zu kommunizieren^^ gibts da bessere mögl.?

2. problem: wird eine klasse selber geschrieben und eingebunden. dann kümmert sich "qt" nicht drum und es bleibt auch speicher zurück! grund sollte klar sein.

und dann ist es noch so ne sache mit der theorie und der praxis... wird das komplette chield oder nur teile aus dem speicher entfernt. könnte mal jemand einen test machen?
 
nicht von qt an sich. die widgets sind alle als "ordentliche" klassen mit nem destruktor geschrieben. bei beenden wirde das widget also delete-d.
Bist Du sicher, dass Du da nicht etwas verwechselst? Wenn man innerhalb eines scopes (einer Funktion, einem Block) mit 'new' etwas erstellt, sei es ein Typ oder eine Klasse, dann wird dieses Objekt nicht automatisch freigegeben, wenn der Block oder die Funktion beendet wird. Man muss irgendwo explizit delete ausfuehren. Ein Beispiel:
Code:
class B {
    private:
        int b;
    public:
        B(int y): b(y){}
        ~B(){}
};

class Foo{
    private:
        B* b;
    public:
        Foo(int m){ b = new B(m); }
        ~Foo(){ }
};


int main()
{
    Foo* f;

    f = new Foo(3);
    delete f;
    return 0;
}
Wenn ich dieses Programm laufen lasse und mit valgrind starte, bekomme ich die Meldung, dass ich 4 bytes verloren habe, naemlich b;
Wenn ich in den Destruktor von Foo ein 'delete b' reinschreibe, verschwindet genau diese Meldung, was ich auch erwarte.

Bei dem Qt-Beispiel, das ich angegeben habe, vermisse ich eben dieses delete. Mehr noch, in den Funktionen werden new's benutzt. Wenn ich die alle im destruktor sauber loeschen will, wird das Programm sehr, sehr schwer pflegbar, und das widerspricht genau der Philosophie von C++.

Falls es so einen Mechanismus wie pinky ihn angesprochen hat, gibt, dann ergibt sich das ganze Problem natuerlich, weil dann mein Beispielprogramm nicht auf Qt uebertragbar ist. Dazu haette ich gerne eine Referenz.

Oder uebersehe ich noch etwas Wichtiges?
 
In der Trolltech-Dokumentation findet man das in wenigen Minuten.
http://doc.trolltech.com/4.2/qwidget.html#QWidget
QWidget::QWidget ( QWidget * parent = 0, Qt::WindowFlags f = 0 )

Constructs a widget which is a child of parent, with widget flags set to f.

If parent is 0, the new widget becomes a window. If parent is another widget, this widget becomes a child window inside parent. The new widget is deleted when its parent is deleted.
Außerdem:
http://doc.trolltech.com/4.2/qwidget.html#dtor.QWidget
QWidget::~QWidget ()

Destroys the widget.

All this widget's children are deleted first. The application exits if this widget is the main widget.
Man kann übrigens auch einen auto_ptr verwenden um sich das lästige deleten zu sparen.
sbrk() wurde mittlerweile aus POSIX entfernt und in der SUS als deprecated markiert.
 
In der Trolltech-Dokumentation findet man das in wenigen Minuten.
http://doc.trolltech.com/4.2/qwidget.html#QWidget
[...]
Das ist schon alles richtig. Allerdings werden in dem Beispiel, das ich anfangs nannte, eine Menge Widgets ohne 'parent' erzeugt. Sie erscheinen zwar innerhalb des Hauptfensters, und man koennte meinen, dass z.B. die QGroupBox dafuer sorgt, alles sauber aufzuraeumen.
Wenn ich das Beispiel jedoch per cut-and-paste erstelle und mit valgrind druebergehen, bekomme ich etwa 500000 fehlende Bytes, und das ist ja wohl kein gutes Zeichen!
 
Tut mir leid, wenn ich mich dumm anstelle, aber fuer mich ist noch nichts geklaert. Ich weiss immer noch nicht, wie man unter Qt korrekt mit Speicherallokation umgeht. Und da KDE auf Qt aufbaut, gehe ich mal davon aus, dass es schon einen Weg gibt, den Speicher auch korrekt wieder freizugeben.
 
Ich weiss immer noch nicht, wie man unter Qt korrekt mit Speicherallokation umgeht.
So wie in jedem anderen C++-Programm auch, von der oben erklärten Ausnahme abgesehen! Und wenn im o. g. Beispiel Speicher verloren geht, dann ist es eben schlecht programmiert. Was gibt es da jetzt nicht zu verstehen?
 
wenn ihr einfach nach einem new das objekt auch wieder deleted ist alles in ordnung^^

aus diesem grund sollte jeder, niemals auf ein delete verzichten.
 
ja, das habe ich aber nicht gesagt. oder sagen wollen^^
 
Wie gesagt, es wundert mich, dass die offizielle Qt-Dokumentation Beispiele zeigt, bei denen der Speicher nicht sauber befreit wird. In einigen Beispielen ist es gar unmoeglich, den Speicher wieder freizugeben. Ich haette von Qt eine sauberere API erwartet.
 
Wie gesagt, es wundert mich, dass die offizielle Qt-Dokumentation Beispiele zeigt, bei denen der Speicher nicht sauber befreit wird. In einigen Beispielen ist es gar unmoeglich, den Speicher wieder freizugeben. Ich haette von Qt eine sauberere API erwartet.

Wie gesagt, das Beispiel ist korrekt. Du kannst dir auch "real-world" KDE oder Qt Apps ansehen, dass ist ganz normal so. Begründing habe ich ja schon geschrieben.

Wenn valgrind da noch was anzeigt, muss das nicht unbedingt der Tatsache entsprechen. Ich erinnere mich an eine Diskussion (ich glaube gtkmm Mailingliste) wo ein ähnliches Phänomen diskutiert wurde. Leider weiß ich die Begründung nichtmehr auswendig, kannst dich ja mal im Archiv der ML oder mit google umsehen.
 
Zuletzt bearbeitet:

Ähnliche Themen

Zwei Fragen zu QT

Zurück
Oben