reinterpret_cast und "generische" Handles



  • Hallo 🙂

    Damit ich in Zukunft meine Klassen plattformübergreifend implementieren kann, nutze ich für die System-spezifischen Typen einfach einen Integer Handle-Typ (intptr_t) - manchmal auch vorbeugend mehrere.
    Mein ganzes Vorhaben geht von der Idee "Ein Header - mehrere Implementierungen" aus.

    Bei einer Windows-Implementierung, reinterpret_caste ich dann den intptr_t& in einen entsprechenden HANDLE&-Typ um und kann dann das Handle mit der native API nutzen. Ebenso unter Linux. Obwohl nur als theoretisches Experiment gedacht funktioniert es ähnlich mit C++/CLI - intptr_t "handlet" ein GC-Handle (was man von gcroot so alles lernen kann 😃 ).

    Für den Fall, dass ein natives "Handle" größer als intptr_t ist, wird es auf dem Heap angelegt und der intptr_t bekommt den Pointer dort hin ... ein kleines template, dass beim Zugriff den intptr_t umschließt macht das auch ganz brav.

    Jetzt frage ich aber dennoch mal die Experten: Ist denn sowas sinnvoll?

    Ich könnte ja die System-Typen gleich im Header deklarieren, etwa in der Form

    class ProcessInfo
    {
    ...
    private:
    #ifdef SYS_WIN
    	HANDLE	_handle;
    #endif
    
    #ifdef SYS_POSIX
    	pid_t	_handle;	
    #endif
    
    #ifdef SYS_CLI
    	gcroot<System::Diagnostics::Process^> _handle;
    #endif
    };
    

    Ähnlich macht es ja boost wo einfach andere Header included werden und native Typen getypedeft werden... allerdings nicht gerade zum Vorteil der Lesbarkeit in den Headern. Nachdem ich ohnehin die Implementierung in eine statische Bibliothek kompiliere, möchte ich die Header übersichtlich halten und ich will weiters auch die Abhängigkeiten des headers (zb. von windows.h, unistd.h, ...) reduzieren. Da führt ja kein Weg an so einem "generischen" Handle vorbei, oder?

    Also, haltet ihr das für sinnvoll eine Bibliothek so aufzubauen oder bietet der boost-Weg ungeahnte Vorzüge?

    Danke für alle Infos 🙂

    lG XOR



  • Das ist kein C++, sondern C++/CLI.



  • 1. Ist das kein C++.
    2. Macht das nur dann Sinn, wenn du wirklich alle Plattformen so genau kennst, dass du weißt wo die Unterschiede liegen, sonst war's viel aufwand für nichts.
    3. Wird der Code dadurch natürlich extrem lesbar
    4. Bist du mit C++/CLI sowieso eingeschränkt.



  • Janjan schrieb:

    Das ist kein C++, sondern C++/CLI.

    Nein, soll es eben nicht sein. Es geht um Portierbarkeit und ich wollte nur anfügen, dass es theoretisch möglich wäre mit einem "generischen Handle" im Header eine managed-Implementierung zu verstecken. Sinnvoll ist es eher nicht, weil das dotNet Framework die meisten Features bereits in schönen Klassen mitbringt, die unter Windows/Linux nicht einheitlich durch eine API abgedeckt sind. Da wäre es ziemlich dumm in C++/CLI die Bibliothek zu nutzen, wo das Objekt unmanaged erzeugt wird, aber die Implementierung wieder managed Objekte einsetzt ... aber ... es geht 😃

    Falls das Thema hier falsch ist, wo gehört es denn hin? Ich will doch wissen wie man besser einen plattform-unabhängigen Header schreibt, dessen Implementierungen dann auf jedem System anders aussehen ... für natives C++. Vergesst also den Hinweis auf C++/CLI. Bei mir sieht der Heaer derzeit ja so aus

    class ProcessInfo
    {
    ...
    private:
      intptr_t _handle;
    };
    

    Macht doch zB. boost/thread/win32/thread_primitives.hpp auf ... Ich will doch nur wissen, ob es sinnvoller ist sowas im Header zu schreiben oder ob sowas nur im cpp file stehen soll (damit man die Abhängigkeiten nicht mitschleppt) 🙄

    lG XOR



  • idR macht man es so, dass man in einer header Datei die jeweiligen typedefs setzt.

    Du nennst es zB process_t und machst daher irgendwo in einer je nachdem mehr oder weniger zentralen header datei folgendes:

    #if defined(SYS_WIN)
        typedef HANDLE process_t;
    #elif defined(SYS_POSIX)
        typedef pid_t process_t;
    #elif defined(SYS_CLI)
        typdef gcroot<System::Diagnostics::Process^> process_t;
    #else
    #error "unsupproted platform"
    #endif
    

    dann kannst du ganz locker als interface sowas anbieten:

    void terminate_process(process_t handle);
    

    und terminate_process wird dann je nach system eben anders implementiert.



  • Aber managed und native zu supporten halte ich definitiv für Schwachsinn...
    Simon



  • theta schrieb:

    Aber managed und native zu supporten halte ich definitiv für Schwachsinn...
    Simon

    Da schließe ich mich an.

    Wenn du wirklich mehrere Plattformen supporten willst, dann mach es so wie Shadow of Mine es geschrieben hat und lass die Typbezeichnungen so wie sie sind und verändere sie in einer extra Header. Ansonsten kann man den Code nämlich nicht wirklich gut lesen.


Anmelden zum Antworten