Pointer innerhalb Klasse auf Memberfunktion



  • nein natürlich nicht.

    Ich halte die Vorgehensweise dennoch für schlauer, dass man auch normale Funktionen übergeben kann, die dann intern aufgerufen werden. Das macht alles ein wenig einfacher.

    Ich bekomme jedoch bei der Zuweisung von "ret" eine Exception

    unsigned long __stdcall ThreadProxy( void* args )
    {
    	ThreadProxyData* data = reinterpret_cast<ThreadProxyData*>(args);
    	DWORD ret = data->start_address_(data->arglist_);
        delete data;
        return ret;
    }
    


  • 😮
    Funktionen "castet" man nicht.

    Ich übergebe an den nächsten Hilfsbereiten. Meine Zeit für heute ist um.



  • Sebastian Pizer schrieb:

    😮
    Funktionen "castet" man nicht.

    Ich meinte auch nicht die Funktion die gecastet wird. Hier wird doch einfach eine struct gecastet, die dann die Adresse der Funktion und deren Parameter enthält oder etwa nicht?



  • Hier ist ein letztes und vollständiges Beispiel, welches das Prinzip verdeutlichen soll, mit dem man Elementfunktionen aufrufen kann, obwohl man einen Zeiger auf eine freie Funktion übergeben muss. Der Schlüssel zur Lösung ist hier der void*-Parameter.

    #include <iostream>
    
    typedef void thread_funktion_t(void*);
    
    void ruf_auf(thread_funktion_t* pf, void* kontext)
    {
      pf(kontext);
    }
    
    class MeineKlasse
    {
    public:
      void foo();
    };  
    
    void MeineKlasse::foo()
    {
      std::cout << "Hallo!\n";
    }
    
    void proxy_MeineKlasse_foo(void* kontext)
    {
      static_cast<MeineKlasse*>(kontext)->foo();
    }
    
    int main()
    {
      MeineKlasse o;
      ruf_auf(proxy_MeineKlasse_foo,&o);
    }
    

    Wenn Du damit jetzt nichts anfangen kannst, solltest Du die Finger von Threads lassen.



  • Sebastian Pizer schrieb:

    Wenn Du damit jetzt nichts anfangen kannst, solltest Du die Finger von Threads lassen.

    Doch doch, dass ist mir doch auch klar. Die Frage geht eigentlich in eine andere Richtung mittlerweile.

    Wie kann ich es anstellen, dass ich meiner Thread Klasse eine Funktion mit beliebiger Konvention übergebe, so wie es ja anscheinend boost::thread macht?
    Ich meine, dass bekomme ich natürlich schon hin:

    typedef unsigned (__stdcall *func)(void*);
    	func f = static_cast<func>(this->_lpFunction);
    	this->_hThread = mybeginthreadex( NULL,
    									  0,
    									  f,
    									  this->_lpParams,
    									  CREATE_SUSPENDED,
    									  0 );
    

    aber wenn _lpFunction ein void* ist, wird logischerweise der Stack nicht korrekt bereinigt. Mich würde interessieren, wie man diese Problematik lösen kann.



  • FrEEzE2046 schrieb:

    Die Frage geht eigentlich in eine andere Richtung mittlerweile.

    Wie kann ich es anstellen, dass ich meiner Thread Klasse eine Funktion mit beliebiger Konvention übergebe, so wie es ja anscheinend boost::thread macht?

    Mit einer Kombination aus Templates und Laufzeitpolymorphie. Die Technik heißt dann "Type Erasure".



  • Sebastian Pizer schrieb:

    Mit einer Kombination aus Templates und Laufzeitpolymorphie. Die Technik heißt dann "Type Erasure".

    Da lohnt sich der Aufwand nicht wirklich, würde ich sagen.

    Ein Problem hat deine Lösung jedoch noch:
    1. Die Thread-Funktion selbst startet die eigentlich Funktion die durch den Thread ausgeführt werden soll und muss außerhalb der Klasse deklariert sein.
    2. Damit muss die eigentliche Thread-Funktion (innerhalb der Klasse) unbedingt public sein, damit ich sie aufrufen kann ...

    nicht unbedingt die eleganteste Lösung



  • FrEEzE2046 schrieb:

    Ein Problem hat deine Lösung jedoch noch:
    1. Die Thread-Funktion selbst startet die eigentlich Funktion die durch den Thread ausgeführt werden soll und muss außerhalb der Klasse deklariert sein.
    2. Damit muss die eigentliche Thread-Funktion (innerhalb der Klasse) unbedingt public sein, damit ich sie aufrufen kann ...

    Es war keine "Lösung" sondern ein Beispiel, welches Dir etwas verdeutlichen sollte.

    nicht unbedingt die eleganteste Lösung

    🙄



  • Sebastian Pizer schrieb:

    FrEEzE2046 schrieb:

    Ein Problem hat deine Lösung jedoch noch:
    1. Die Thread-Funktion selbst startet die eigentlich Funktion die durch den Thread ausgeführt werden soll und muss außerhalb der Klasse deklariert sein.
    2. Damit muss die eigentliche Thread-Funktion (innerhalb der Klasse) unbedingt public sein, damit ich sie aufrufen kann ...

    Es war keine "Lösung" sondern ein Beispiel, welches Dir etwas verdeutlichen sollte.

    nicht unbedingt die eleganteste Lösung

    🙄

    Ja, okay - aber soll das etwa heißen, dass es keine Lösung für das Problem gibt? Es wird doch wohl möglich sein einen Thread aus einer Klasse heraus zu starten


  • Mod

    Nichts hindert dich, eine statische Memberfunktion zu verwenden.



  • FrEEzE2046 schrieb:

    Ja, okay - aber soll das etwa heißen, dass es keine Lösung für das Problem gibt?

    Welches Problem? Gibt es noch eins?

    FrEEzE2046 schrieb:

    Es wird doch wohl möglich sein einen Thread aus einer Klasse heraus zu starten

    Falls Du damit meinst, einen Thread eine Elementfunktion ausführen zu lassen: Klar, das geht! Siehe boost::thread, boost::bind und als "type erasure"-Beispiel noch boost::function. Ich werde Dir das hier nicht vorkauen. Du hast genug Stichwörter bekommen. Recherchiere selbst. Es lohnt sich!

    Gruß,
    SP



  • Ich werde es mir anschauen. Ich habe es auf die schnelle erst ein mal so gelöst:

    template< typename THREAD_ROUTINE >
    struct ThreadProxyData
    {
    	THREAD_ROUTINE	 lpFunction;
    	THREAD_DATA		 lpParams;
        ThreadProxyData( THREAD_ROUTINE start_address, THREAD_DATA arglist) : 
    					 lpFunction(start_address), lpParams(arglist) {}
    };
    

    Diese struct wird jetzt dem Konstruktor übergeben. Insofern ist dort bereits festgelegt, wie die Funktion aussieht. Intern rufe ich dann eine andere Funktion des Typs unsigend (__stdcall *Func)(void*) auf, welche wiederum dann diese Funktion aufruft.

    Ist eine - denke ich - ganz gute Lösung.



  • Wie ich nun einen Zeiger auf eine Klassenmethode bekomme hat sich dadurch natürlich immer noch nicht geklärt. Ich löse das jetzt wie folgt:

    // Funktion außerhalb Klasse
    unsigned int __stdcall __callAccept(void* _instance)
    {
    	while( TRUE ) {
    		static_cast<HClasses::ServerSocket*>(_instance)->_accept( NULL );
    	}
    	return 0;
    }
    
    // innerhalb Klasse
    	this->_acceptThread = new Threading::HThread( __callAccept,
    		                                          this,
    												  HClasses::Threading::PREPARED,
    												  false                           );
    

    Naja, eine wenig schöne Lösung. Fällt jemandem eine elegantere Art ein?



  • Ein Zeiger auf eine nicht-statische Elementfunktion ist nicht kompatibel zu einem Zeiger auf eine freie Funktion. Es gibt auch keine Zeiger auf "gebundene" Elementfunktionen.

    Das, was Du jetzt geschrieben hast, ist in etwa das gleiche, was ich als erste Antwort in diesem Thread geschrieben habe. Es ist erstaunlich, wie lange es gedauert hat...

    Fällt mir etwas eleganteres ein? Naja, im Prinzip kommst Du um so etwas nicht herum. Man kann aber diesen Proxy-Schnickschnack hinter der Threading-Bibliothek verstecken. Das wär dann nach meinem Empfinden elegant. Das sage ich allerdings auch nicht zum ersten Mal. Und bevor ich mich weiter wiederhole, werde ich jetzt mal ganz direkt: Du demonstrierst Inkompetenz. Das allein ist keine Schande. Es ist noch kein Meister vom Himmel gefallen. Du bist aber nicht in der Lage gewesen, anhand der Hinweise und Tipps, die man Dir gab, Dir selbst zu helfen. Das ist eine sehr schlechte Voraussetzung zum Schreiben einer eigenen Threading-Bibliothek. Was erwartest Du? Dass man Dir hier eine Komplettlösung anbietet? Das kannst Du haben: Nimm boost::thread. Wenn Du etwas ähnliches selbst bauen willst, bitte. Du kannst dann eine Suchmaschine zu den Stichwörtern befragen, die hier gefallen sind und selbst eine Lösung erarbeiten.

    Gruß,
    SP



  • Ich bleibe mal ruhig und behaupte wir reden einfach ständig aneinander vorbei.

    Ich bin mir darüber im klaren, dass die jetzige Lösung genau das ist, was du am Anfang vorgeschlagen hast. Ich habe "damals" gesagt, dass ich die Lösung nicht schön finde und sage jetzt, dass ich "meine" Lösung nicht schön finde.
    Alles sehr logisch, würde ich sagen.

    Meine Frage war doch einfach nur, ob es INNERHALB der Klasse möglich ist (ohne von außen zu kommen) einen Zeiger auf eine Memberfunktion zu bekommen.
    Der Grund, warum es so lange gedauert hat, war eher der, dass ich keine "eindeutige" Verneinung bekommen habe.

    Die Lösung die wir jetzt haben war mir schon eingefallen, bevor ich diesen Thread geschrieben habe, daher war ich auch überhaupt nicht darauf eingegangen (worüber du dich dann später aufgeregt hast), weil es unsauber ist.

    Ich habe mich derweil auch mal ein bisschen mit boost::function auseinander gesetzt. Es dient zwar überhaupt nicht mehr meiner Problemlösung, aber schien mir doch recht interessant zu sein.

    Anhand von "function.hpp" entnehme ich, dass es sich dabei im Prinzip um eine Verschachtelung von templates handelt. Man übergibt typename Signature, was intern dann aufgesplittet wird (siehe function0 .. function10).

    Was mich jetzt interessieren würde, ist, wie man denn den übergebenen Funktionstyp "auswertet" (falsches Wort, schon klar 😉

    angenommen es wird folgendes übergeben:

    boost::function<typename Signature>
    boost::function<int(int,int,int)> f = foo;
    

    innerhalb der Klasse haben wir dann:

    boost::function3<typename R, typename T1, typename T2, typename T3>
    boost::function3<int,int,int,int>
    

    Mich würde interessieren, wie man den ursprünglich übergebenen Typ auswerten kann.

    char* _type = typeid(f).name();
    

    hilft einem nicht viel weiter.

    Ich würde mich freuen, wenn wir das so schön klären könnten, wie das vorherige Thema.


  • Administrator

    FrEEzE2046 schrieb:

    Ich bleibe mal ruhig und behaupte wir reden einfach ständig aneinander vorbei.

    Da habe ich so meine Zweifel, ich könnte mir eher vorstellen, dass du Sebastian Pizer nicht verstanden hast und das aus einem simplen Grund, weshalb ich dir nun eine Frage stelle:
    Wo stehst du in Sachen C++ lernen? Ich persönlich habe das Gefühl, dass du hier ein für dein Wissen viel zu fortgeschrittenes Thema angehen möchtest. Dir fehlen also meiner Meinung nach Grundlagen. Und ohne diese Grundlagen, ist es natürlich eher schwer, dir in dem Bereich zu helfen.

    Was hast du bereits über C++ gelesen, wenn ich mir die Frage erlauben darf? Vielleicht können wir dir entsprechende Literatur vermitteln, welche du zuerst lesen könntest.

    Grüssli



  • Offensichtlich habe ich Probleme mich richtig auszudrücken. Ich denke nicht, dass ich hier etwas versuche, was ich nicht richtig begreife.

    Zugegeben: Mit Templates arbeite ich gewöhnlich nicht, daher auch die letzte Frage. Aber Threads oder Sockets habe ich schon oft erstellt, nur eben nie für eine Methode innerhalb einer Klasse.

    Das ich die Möglichkeit der statischen Deklaration oder des externen Aufrufs habe, wusste ich bereits vorher. Ich dachte nur, dass mir jemand noch eine geschicktere Variante verraten kann.
    Man darf da nicht so kurzsichtig sein. Die Frage sollte irgendwo auch darauf abzielen, dass jemandem vielleicht ein generell anderer Lösungsweg einfällt; das war nicht unbedingt beschränkt auf den Methoden-Pointer.



  • FrEEzE2046 schrieb:

    Ich habe mich derweil auch mal ein bisschen mit boost::function auseinander gesetzt. Es dient zwar überhaupt nicht mehr meiner Problemlösung, aber schien mir doch recht interessant zu sein.

    ...

    Was mich jetzt interessieren würde, ist, wie man denn den übergebenen Funktionstyp "auswertet" (falsches Wort, schon klar 😉

    Hier ist eine halbwegs überschaubare Implementierung auf Basis von C++0x: click. Sie ist nicht perfekt und vielleicht auch nicht besonders leserlich aber das Prinzip sollte klar werden.


  • Administrator

    FrEEzE2046 schrieb:

    Offensichtlich habe ich Probleme mich richtig auszudrücken.

    Kann sein, zum Teil empfand ich es als sehr verwirrend, wie du geantwortet hast. Ich bin mir das oft gewohnt davon, wenn der andere sich nicht so gut im Thema auskennt.

    FrEEzE2046 schrieb:

    Ich denke nicht, dass ich hier etwas versuche, was ich nicht richtig begreife.

    Ich kann es nicht genau beurteilen, solange ich nicht deinen genauen Wissensstand kenne, was man eben mit der Literatur zumindest teilweise hätte feststellen können 😉

    FrEEzE2046 schrieb:

    Man darf da nicht so kurzsichtig sein. Die Frage sollte irgendwo auch darauf abzielen, dass jemandem vielleicht ein generell anderer Lösungsweg einfällt; das war nicht unbedingt beschränkt auf den Methoden-Pointer.

    Im allgemeinen geht man über eine statisch oder globale Funktion und übergibt einen Zeiger auf eine Struktur. Das geht auch gar nicht gross anders, weil es so von den Betriebsystemen vorgeschrieben ist.
    Die Threading Bibliothek kapselt dieses nicht so schöne Aussehen und gibt einem ein allgemeingültiges Interface. Was zum Beispiel eben auch boost::thread macht.

    Nun ist halt die Frage, was willst du genau? Steigst du auf boost::thread um oder kapselst du lieber deine Threading Bibliothek und erstellst dir eine eigene, was aber mit ziemlich viel Arbeit verbunden ist. Sowas zu erstellen ist nicht gerade von heute auf morgen fertig und man sollte dabei schon auch in Templates gefestigt sein.

    Was genau möchtest du also nun von uns hören? Wenn du mehr über Templatemetaprogrammierung wissen willst, dann kann ich dir auch ein oder zwei Bücher empfehlen.

    Grüssli



  • Sebastian Pizer schrieb:

    Hier ist eine halbwegs überschaubare Implementierung auf Basis von C++0x: click. Sie ist nicht perfekt und vielleicht auch nicht besonders leserlich aber das Prinzip sollte klar werden.

    Was ich nicht verstehe ist diese Zeile:

    template<typename R, typename ... P>
    

    Ich bekomme da logischerweiße einen Compilerfehler

    missing ',' before '...'
    

    Was genau soll obige Deklaration bedeuten? Eine nichtdefinierte Parameterliste? Wenn ja, wie spreche ich die übergebenen Werte an?


Anmelden zum Antworten