Zeiger auf eigene Klasse möglich?
-
Warum nicht gleich einen
std::vector<T>
?
Verkettete Listen sind bei modernen Computersystemen eher kontraproduktiv (was das Speichermanagement angeht).
-
@Tyrdal: Ich würde gerne (am ESP32) dynamisch Groupboxen erstellen. Wenn ich die Funktion SERVICE (periodisch) aufrufe, würde ich gerne alle Instanzen durchlaufen und diese bei Bedarf refreshen. Wenn ich mir einfach alle erstellten Instanzen in einem Vector (std::vector<myGroup*>) speichere, dann könnte ich diese einfach abarbeiten und müsste nicht wie bei verketteten Listen die nächste Groupbox angeben.
Edit: Ich glaube ich suche nach (?):static std::vector<myGroup*> pvGroupInstance; ... myGroup* pThisGroupInstance = (this); pvGroupInstance.push_back(pThisGroupInstance);
@Th69: Genau, mir scheint die verkettete Liste auch aufwändiger als meine geplante Lösung, da ich da den Nachfolger angeben muss...
-
Wie werden die Instanzen der Klasse myGroup verwaltet? Falls Du Angst vor dem Kopieraufwand von
std::vector<myGroup>
hast, wärestd::vector<std::unique_ptr<myGroup>>
eine Alternative.
-
@john-0 Er nutzt sowieso Zeiger und der vector soll auch wohl nicht der Owner sein.
-
@Jockelx
Ja, das ist die wahrscheinliche Vermutung. Nur ich würde das gerne bestätigt sehen.
-
@Rainer sagte in Zeiger auf eigene Klasse möglich?:
myGroup* pThisGroupInstance = (this);
pvGroupInstance.push_back(pThisGroupInstance);Wie wärs eigentlich mit:
pvGroupInstance.push_back(this);
?
-
@john-0 sagte in Zeiger auf eigene Klasse möglich?:
Wie werden die Instanzen der Klasse myGroup verwaltet? Falls Du Angst vor dem Kopieraufwand von
std::vector<myGroup>
hast, wärestd::vector<std::unique_ptr<myGroup>>
eine Alternative.Sorry, habe ich erst jetzt gelesen. Ich hoffe ich verstehe die Frage richtig. Im Setup der main.c instanziere ich 3 Groupboxen:
myGroup *grpSetting; myGroup *grpAntrieb; myGroup *grpCutter;
Dank obigen Vektor, den ich mit jeder Instanzierung erweitere, kann ich nun mit einer übergeordneten Funktion den Service aller Instanzen ausführen. Ich finde es auch gut, dass ich die Groupboxen mit deren Namen ansprechen kann (und z.B. nicht über den Index eines weiteren Vektors).
void myGUI::SERVICE(void) { for (auto & GroupInstance : pvGroupInstance) { GroupInstance->SERVICE(); //Service aller Instanzen ausführen } }
Mir scheint die Lösung momentan perfekt. Ehrlich gesagt weiß ich nicht, was Du mir mit der Alternative
std::vector<std::unique_ptr<myGroup>>
vorschlagen möchtest, könntest Du mir das bitte erklären?
-
Die erste Frage, die sich da stellt, ist die, ob man diese Gruppen tatsächlich auf dem Heap per
new
erzeugen muss, oder ob sie nicht einfach als Stackvariablen erzeugt werden können.In modernem C++ werden Praktiken wie
class Demo { MyObject* obj_; public: Demo() { obj_ = new MyObject(); } ~Demo() { delete obj_; } } // Was passiert, wenn das Objekt kopiert wird, also Demo d1; Demo d2 = d1; oder void func() { MyObject* obj = new MyObject(); // do_something delete obj; } // Was passiert, wenn do_something eine exception wirft?
als veraltet und fehleranfällig angesehen (Stichpunkte Rule of 3/5, exception safety) . Für sowas wurden smart Pointer wie
std::unique_ptr
undstd::shared_ptr
entwickelt, die die Lebenszeit eines Objekts verwalten. Du solltest dich unbedingt in das Thema RAII einlesen, wenn du jetzt nicht weißt, wovon ich rede.Die "richtige" Variante von
func
mit einem Objekt, das unbedingt auf dem Heap erzeugt werden muss, sähe so aus:void func() { std::unique_ptr<MyObject> obj = make_unique<MyObject>(); // do something }
Habt ihr coding guidelines? Funktionsnamen, die komplett großgeschrieben werden finde ich übelst, ich lasse mich von meinem Quelltext ungern anschreien. Zumal die Klassennamen CamelCase mit kleinem Anfangsbuchstaben benutzen. Sieht merkwürdig aus...
-
Aber wenn sein vector die Zeiger nicht besitzt, dann ist unique_ptr nicht die richtige Wahl.
-
Ich hatte bisher noch nie einen Anwendungsfall in dem eine (verkettete) Liste die Lösung war.
Die wichtige Frage: soll der Vector die Zeiger besitzen, oder nicht? Willst du den Besitz des Pointers auf den gewünschten Container übergeben oder soll der vector nur eine Randnotiz sein und diese Zeiger eben auch kennen?
Was sind das für Instanzen dieser Klasse? Sind das Pointer, die du von irgendeiner grafischen API bekommst oder legst du die Instanzen selbst an und hast die volle Kontrolle über die Lebenszeit der Instanzen?
-
@Tyrdael: Wird ja auch nirgendwo behauptet. Das einzige, das ich in Frage stelle ist das hier:
myGroup *grpSetting; myGroup *grpAntrieb; myGroup *grpCutter;
Müssen die Objekte zwingend auf dem Heap erzeugt werden? Geht das nicht als normale Stackvariable?
Und falls diese Objekte unbedingt auf dem Heap erzeugt werden müssen, dann ist die Benutzung eines smart_ptr sinnvoll.
-
Danke Leute!
@Tyrdal @DocShoe : Ich mache das (C++) nur als Hobby und bin daher nicht so fit wie Ihr. Daher auch keine (so strengen) coding guidelines. Da ich mit Arduino (ESP32) arbeite, ist nach meinem Verständnis die Klasse am Heap sinnvoll: Diese wird in der Regel insetup()
initialisiert (bzw. durch den Konstruktor) und periodisch inloop()
abgearbeitet. Wenn ich eine Initialisierung und einen Service in meiner Klasse brauche, sind diese Methode daher bei mir in der Regel groß.
@It0101 sagte in Zeiger auf eigene Klasse möglich?:soll der Vector die Zeiger besitzen,
Ich denke schon: Der Vektor merkt sich jede instanziierte Klasse und somit kann ich mit einer übergeordneten Funktion
SERVICE()
alle Methoden SERVICE() der instanziierten Klassen abarbeiten.@It0101 sagte in Zeiger auf eigene Klasse möglich?:
sind das Pointer, die du von irgendeiner grafischen API bekommst oder legst du die Instanzen selbst an und hast die volle Kontrolle über die Lebenszeit der Instanzen
Das ist eine von mir erstellte Klasse, die sich um die Darstellung einer selbst erstellten Groupbox kümmert (Text, Zeilen, Rahmen, Hintergrundfarbe,...)
-
@Rainer sagte in Zeiger auf eigene Klasse möglich?:
Da ich mit Arduino (ESP32) arbeite, ist nach meinem Verständnis die Klasse am Heap sinnvoll: Diese wird in der Regel in
setup()
initialisiert (bzw. durch den Konstruktor) und periodisch inloop()
abgearbeitet. Wenn ich eine Initialisierung und einen Service in meiner Klasse brauche, sind diese Methode daher bei mir in der Regel groß.Bei so kleinen Maschinchen würd ich persönlich eher dazu tendieren überhaupt nicht auf dem Heap zu arbeiten und nach Möglichkeit alles statisch zu machen (nicht zwangsweise auf dem Stack, aber durchaus vergleichbar). Das ganze
new
/delete
will ja schliesslich auch verwaltet werden und so ein dynamischermalloc
/free
-Allokator unter der Haube hat schon einen gewissen Overhead (vor allem bezüglich Speicherbedarf für Metadaten und der Fragmentierung - je nachdem wie dienew
/delete
-Aufrufe in deinem Programm verteilt sind).Da du das aber eh wie du sagst nur als Hobbyprojekt machst, geht das schon okay, solange du keine Speicherprobleme bekommst. Das ist immerhin etwas weniger mühsam als die gesamte Speichernutzung des Programms mit statisch reserviertem Speicher bis ins Detail durchzuplanen. Ich glaube die größeren Arduinos haben auch um die 320KiB Speicher, oder? Das ist ja richtig viel - habe bisher nur nen Arduino Nano programmiert - bei nur 2KiB Speicher überlegt man es sich zweimal, ob an sich wirklich einen dynamischen Speichermanager leisten will
-
@Finnegan Danke für die netten Worte und das Verständnis. Der ESP32 ist echt toll 520KB Ram - echt viel für ein so kleines Ding. Da kratze ich mit meinen Programmteilen irgendwo im % Bereich herum. Richtig rauf geht es mit diversen Libraries. Aber da ist noch viel Luft: RAM: [== ] 15.7% (used 83392 bytes from 532480 bytes).
Enger wird es da schon beim Flahs (4MB), da ich 2 gleich große Partitionen und noch weitere kleine brauche:
Flash: [========= ] 85.4% (used 1566759 bytes from 1835008 bytes). Aber notfalls habe ich noch die 16MB Version...Vielen Dank Leute, dass Ihr euer Wissen mit mir teilt. Ich wünsche euch ein schönes Weihnachtsfest!!!
PS: Ein "kleines" Weihnachtsgeschenk hatte ich auch schon: 200KB Flash: Der ESP war noch auf 320KB eingestellt!