001
30.08.2019, 11:26 Uhr
ao
(Operator)
|
Zitat von adenied: |
Wenn ich mir die ganzen gtkmm Beispiele im Internet anschaue, dann sehen die immer so aus:
Auch Beispiele in denen eigene Klassen von Gtk::Window abgeleitet werden, haben Membervariablen nicht als Pointer angelegt, sondern als Skalar, also z.B.
Meiner Interpretation nach werden dann doch alle GUI-Elemente auf dem Stack erzeugt?! Ist das richtig so, oder macht das irgendwelche Probleme?
|
Im ersten Beispiel (Window-Objekt in main) wird alles auf dem Stack erzeugt, das ist richtig.
Das zweite Beispiel ist nur eine Klassen*definition*, hier wird noch gar kein Speicher verwendet, um irgendwas zu erzeugen. Das Button-Member wird im gleichen Speicher liegen wie das umgebende MyWindow-Objekt.
Probleme macht sowas in der Regel nicht, im Gegenteil, es ist am einfachsten so, weil man sich um delete und den richtigen Zeitpunkt dafür nicht kümmern muss, im Gegensatz zu verpointerten Objekten.
Zitat: |
Rein theoretisch könnte ich ja die Variable window aus dem ersten Snippet und die Membervariable _button aus dem zweiten Snippet als Pointer anlegen und _button dann im Destruktor der Klasse MyWindow mit delete selber löschen?! Ist das sinnvoll oder eher nicht?
|
Sinnvoll ist immer die einfachste Lösung, die die Anforderungen erfüllt. Im Allgemeinen ist das so wie in deinen Beispielen. Da die Nachteile von Pointern gravierend sind, sollte man sich nur aus guten Gründen für Pointer entscheiden.
Ein Argument für einen Pointer auf den Button wäre zum Beispiel, wenn sich erst später entscheidet, welcher Button dort angelegt werden soll oder wenn er zur Laufzeit ausgewechselt wird - einen Grund dafür müsste ich jetzt an den Haaren herbeiziehen, aber egal.
Ein Argument für einen Pointer auf Window in der main wäre es, wenn das Fenster derart viele interne Daten anlegt, dass das den Stack sprengen würde - auf PCs mit Gigabytes von RAM eher kein Thema, aber auf kleinen Systemen (Raspberry-Pi oder kleiner) kann es nötig sein, das im Auge zu behalten. Mit einem vernünftigen Klassen-Entwurf kann man aber dafür sorgen, dass die großen Datenmengen außerhalb der Klasse selbst lagern (z.B. indem man Membervariablen als std::vector<int> myData deklariert und nicht als int myData[RIESEN_GROSSES_DINGSBUMS]). Das hat auch noch andere Vorteile (Kompatibilität mit Standard-Iteratoren und Standard-Algorithmen, ...).
Darüberhinaus gibt es in C++ aber auch Referenzen und (seit C++11) auch leistungsfähige Smart-Pointer (std::shared_ptr und std::unique_ptr, zum Nachschlagen), die das Arbeiten mit Zeigern wesentlich angenehmer machen. Achtung: Den std::auto_ptr (aus C++03) nicht verwenden, der war nicht richtig zuende gedacht und nicht sinnvoll benutzbar (peinliche Panne). Der ist seit C++11 "deprecated" (Hinweis beim Kompilieren) und seit C++17 entfernt (Compiler bricht mit Fehlermeldung ab).
Insgesamt sind die alten Raw-Pointer häufig nur eine schlechte Lösung für Probleme, die man mit besserer Kenntnis der Sprache gar nicht hätte. In modernem C++ braucht man die für nichts mehr, außer um kompatibel zu sein mit altem Code oder mit C-Code. Dieser Post wurde am 30.08.2019 um 12:32 Uhr von ao editiert. |