staging.inyokaproject.org

Meinung zu: Zeiger auf sich selbst (C++)

Status: Ungelöst | Ubuntu-Version: Ubuntu MATE 18.04 (Bionic Beaver)
Antworten |

Dakuan

Avatar von Dakuan

Anmeldungsdatum:
2. November 2004

Beiträge: 6532

Ist es sehr verwerflich, wenn ein Objekt (Anwendung) einen statischen Zeiger auf sich selbst bereit stellt?

Ich habe immer wieder mal Probleme mit Callback Funktionen. Diese müssen ja statisch sein und gehören damit zwar zur Klasse, haben aber keinen Bezug zur aktuellen Instanz. Das ist kein Problem, wenn ein Objekt, das einen Callback auslöst, in das Hauptfenster einer Anwendung eingebettet ist. Ich kann dann immer das Parent Fenster ermitteln, da die Callback Funktion immer einen Zeiger auf das verursachende Objekt bekommt.

Das funktioniert aber nicht, wenn der Verursacher ein eigenständiges Fenster ist (das keinen Parent hat). Bisher habe ich in solchen Fällen den Objekten einen Zeiger auf den Eigentümer mitgegeben, welcher dann im Callback verwendet wird. Das macht die Sache aber recht umständlich.

Die Zuordnung zum Hauptfenster wird immer dann benötigt, wenn Daten zwischen Objekten ausgetauscht werden sollen, die sich eigentlich nicht kennen (sollen).

Ich habe auch schon versucht, herauszufinden wie das bei Qt gemacht wird, aber das war wir im ersten Anlauf nicht wirklich gelungen.

So ein Self-Pointer scheint mir da eine ziemlich einfache Lösung zu sein um einem Vermittler die Arbeit zu erleichtern. Oder gibt es da schwere Bedenken?

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13242

Ich bin mir nicht 100% sicher, dass ich Deinen Anwendungsfall richtig verstanden habe.

Also, ein static ist ja pro Klasse nur ein Mal da (also genau genommen eine globale Variable), also kannst Du auch nur auf ein Objekt zeigen. Das beißt sich damit, dass man etliche Objekte einer Klasse haben kann (wenn ich Deinen Anwendungsfall richtig deute). Damit verbietet es sich, ein static dazu zu benutzen auf eine bestimmte Instanz zu zeigen. Auch wenn das nur vorübergehend genutzt wird, öffnest Du damit allen möglichen Problemen die Tür (Multithreading).

Benutzt Du eine C-Bibliothek für die grafische Oberfläche? Normalerweise kann man doch solchen Funktionen einen void-Zeiger auf irgendwas mitgeben. Gibt es das in Deinem Fall nicht auch? Damit könntest Du dann beliebige Informationen transportieren.

Weiterer Gedanke: ist der Datenaustausch nicht eigentlich eine Sache, die im Modell passiert und nicht in den UI-Elementen? Vielleicht brauchen wir noch mehr Details.

Dakuan

(Themenstarter)
Avatar von Dakuan

Anmeldungsdatum:
2. November 2004

Beiträge: 6532

rklm scrieb:

Das beißt sich damit, dass man etliche Objekte einer Klasse haben kann (wenn ich Deinen Anwendungsfall richtig deute). Damit verbietet es sich, ein static dazu zu benutzen auf eine bestimmte Instanz zu zeigen.

Das sehe ich nicht ganz so, da es sich hier um das Hauptobjekt (Fenster) handelt, von dem es definitiv nur eine Instanz gibt.

Bei meinen ersten Versuchen eine GUI zu erstellen hatte ich dazu tatsächlich einen (echten) globalen Pointer verwendet, der vom Konstruktor des Hauptfensters initialisiert wurde. Da globale Variablen aber immer "verteufelt" werden, habe ich später versucht ohne auszukommen.

Auch wenn das nur vorübergehend genutzt wird, öffnest Du damit allen möglichen Problemen die Tür (Multithreading).

Darin sehe ich eigentlich kein Problem, da dies ja ein Zeiger auf das Hauptfenster ist, welches in den meisten Toolkits als einziges Objekt Zugriff auf den grafischen Output hat. Von daher müssen sich ggf. alle anderen Objekte (Threads) irgendwie mit dem Hautfenster abstimmen.

Benutzt Du eine C-Bibliothek für die grafische Oberfläche? Normalerweise kann man doch solchen Funktionen einen void-Zeiger auf irgendwas mitgeben. Gibt es das in Deinem Fall nicht auch? Damit könntest Du dann beliebige Informationen transportieren.

Es geht um C++ (FLTK, was ich absichtlich erstmal nicht erwähnt hatte). Das Problem ist, das hier normalerweise nur 2 Informationen mitgegeben werden: ein Zeiger auf das Widget und ein (void)pointer. Das reicht aber in einigen Fällen nicht aus.

Also wenn z.B. unterschiedliche Objekte (Widgets) das Haupfenster veranlassen möchten, eine bestimmte Aktion auszuführen und der (void)pointer die Aktion angibt, ist das nicht ausreichend. Denn da fehlt zur Ausführung der Bezug zum Hauptfenster (wenn das auslösende Objekt ein eigenständiges Fenster ist und nicht in das Hauptfenster eingebettet ist). Da könnte dann so etwas wie:

    MainWindowPointer->AnderesObjekt->GewünschteAktion()

hilfreich sein. Bei eingebetteten Objekten kann man den Zeiger auch über die Funktionen:

    window(w);
    parent(w);

ermitteln.

Ohne einen solchen "self-pointer" währen die Alternativen den Widget-Pointer immer auf das Hauptfenster zeigen zu lassen (was nicht der eigentlichen Definition entspricht, und auch den Zugriff auf die Objektdaten verhindert). Oder man müsste den (void)pointer immer auf einen Datenblock zeigen lassen, der dann auch den Besitzer des Objekts als Bezug enthält, was dann aber den Overhead erhöht.

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13242

Dakuan schrieb:

rklm scrieb:

Das beißt sich damit, dass man etliche Objekte einer Klasse haben kann (wenn ich Deinen Anwendungsfall richtig deute). Damit verbietet es sich, ein static dazu zu benutzen auf eine bestimmte Instanz zu zeigen.

Das sehe ich nicht ganz so, da es sich hier um das Hauptobjekt (Fenster) handelt, von dem es definitiv nur eine Instanz gibt.

Gut, das ergibt insofern Sinn, als es davon a) nur eins gibt und b) sich das nicht ändert.

Oder man müsste den (void)pointer immer auf einen Datenblock zeigen lassen, der dann auch den Besitzer des Objekts als Bezug enthält, was dann aber den Overhead erhöht.

Was mir dann aber als das sauberere Vorgehen erscheint. Das ist ja absichtlich ein void-Zeiger, weil man da beliebige Informationen mitschicken soll, die für die Ausführung des Callbacks wichtig sind. (Ohne jetzt das Toolkit genau zu kennen - das ist einfach übliche Praxis).

Aber: nach MVC sollte der Zustand ja im Modell gespeichert werden. Welche Daten musst Du denn da überhaupt austauschen?

Dakuan

(Themenstarter)
Avatar von Dakuan

Anmeldungsdatum:
2. November 2004

Beiträge: 6532

Welche Daten musst Du denn da überhaupt austauschen?

Z.B. Dateinamen alt und neu nach einer Umbenennung. Diese Änderung muss dann auch in einem anderen Objekt (Thumb-Viewer) durchgeführt werden. Momentan mache ich das in mehreren Schritten, indem erstmal der Grund für den Rückruf abgefragt wird (habe ich so in anderen Quelltexten gesehen).

Beispiel:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
void MainWindow::renamer_cb( Fl_Widget * w, void * u ) {
    MainWindow * mwp = (MainWindow*)u;
    Renamer * rnp = (Renamer*)w;
    const char * on;
    const char * nn;

    switch( rnp->reason() ) {
        case 1:
            mwp->scan_dir();
            break;
        case 2:
            rnp->get_names( &on, &nn );
            mwp->tview->rename( on, nn );
            break;
        ...
    }
}

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13242

Dakuan schrieb:

Welche Daten musst Du denn da überhaupt austauschen?

Z.B. Dateinamen alt und neu nach einer Umbenennung. Diese Änderung muss dann auch in einem anderen Objekt (Thumb-Viewer) durchgeführt werden.

Vielleicht entgeht mir ja noch etwas, aber das klingt doch 1a wie eine Änderung im Modell, die dieses per Callbacks an alle interessierten (UI-Elemente) meldet. Warum müssen die UI-Elemente denn überhaupt etwas voneinander wissen?

Dakuan

(Themenstarter)
Avatar von Dakuan

Anmeldungsdatum:
2. November 2004

Beiträge: 6532

Warum müssen die UI-Elemente denn überhaupt etwas voneinander wissen?

Genau das sollen sie eigentlich nicht. Ich versuche da eher so etwas wie eine Zentrale zu schaffen, die das alles koordiniert (ähnlich Mediator).

Antworten |