C++-Designfrage
-
Hallo,
ich habe folgendes Programm: In einer while-Schleife werden einzelne Bilder aus einem Video ausgelesen. Mit einer Klasse Painter soll auf den Bilder gezeichnet werden können. Bedingung: Der Painter soll auf dem Originalbild zeichnen, also keine eigene Kopie speichern:
// Pseudocode Painter p; while(readFrame()) { Image img = readImage(); p.setImage(img); // Soll nur Referenz speichern // [...] zeichnen mit Painter, Darstellung usw. }Wie realisiert man das am besten, so dass auch immer gleich sichergestellt wird, dass das Bild, was dem Painter zugeordnet wurde, auch stets existiert. Der beste Ansatz, der mir einfällt wäre folgender:
// Beispielcode class PainterPointer { public: PainterPointer(Image *to) : myImage(to){ } void draw(); void drawX(); void drawY(); private: Image* myImage; }; // Pseudocode Painter p; while(readFrame()) { Image img = readImage(); p.setImage(&img); // Soll nur Referenz speichern // [...] zeichnen mit Painter, Darstellung usw. }In den zeichnen Methoden des Painters wie draw oder drawX müsste man dann immer prüfen, ob zumindest der Pointer gesetzt wurde:
void drawX() { if(myImage) { } }Gibt's da noch einen besseren Ansatz?
-
Du könntest statt einem Pointer eine Referenz benutzen. So ist sichergestellt, dass zumindest immer ein zum Zeitpunkt des Aufrufs von setImage gültiges Objekt übergeben wird. Da in deinem Beispiel Image aber auf dem Stack angelegt wird, musst Du sicherstellen, dass das Objekt noch existiert, wenn du PainterPointer-Methoden nutzt. Der Aufruf if(myImage) hilft da nur bedingt weiter, denn der prüft nur, ob kein NULL-Pointer übergeben wurde und nicht, ob der Pointer noch auf was gültiges zeigt.
Irgendwie kapier ich den Sinn des zweiten Code-Stücks aber nicht. Welche Signatur hat Painter::setImage? Nimmt das ein PainterPointer-Objekt entgegen so dass der Pinter auf Image implizit konvertiert wird durch den Konvertierungs-Konstruktor oder nimmt das gleich ein Image* entgegen? In dem Fall wäre PainterPointer nutzlos.
-
Mit deinem momentanen Ansatz wird das Bild zerstört, was den Zeiger invalidiert. Aber du könntest z.B. sowas machen:
std::auto_ptr<Image> readImage(); void Painter::SetImage(std::auto_ptr<Image> image); // ... Painter p; std::auto_ptr<Image> image = readImage(); p.setImage(image);Oder direkt:
p.setImage(readImage());
-
Nexus schrieb:
Mit deinem momentanen Ansatz wird das Bild zerstört, was den Zeiger invalidiert. (snip)
Also von der Objekt-Lifetime her ist das schon in Ordnung, da das Image-Objekt bis zum Ende des while-Blocks lebt. Wenn die Methoden, die auf dem Image-Objekt arbeiten, nur innerhalb des while-Blocks aufgerufen werden (und so versteh ich den Kommentar), ist das imho schon in Ordnung, oder überseh ich was?
-
Nein, das wäre schon in Ordnung. Aber dann verstehe ich nicht, warum
PainterdasImageüberhaupt speichert. Dieses kann doch direkt an die Memberfunktionen übergeben werden?Painter painter; while (...) { Image image = ...; painter.draw(image); ... }Oder, wenn
Painternur eine Hilfsklasse fürs Zeichnen ist, warum ist dessen Instanz bereits ausserhalb der Schleife deklariert? Ich würde es in diesem Fall eher so lösen:while (...) { Image image = ...; Painter painter(image); painter.draw(); ... }