PIMPL und Typedef in der versteckten Klasse



  • Kompilierzeit verringern

    Das ist heute kein Problem.

    Pimpl benutze ich aehnlich wie cooky, um Plattformabhaengigkeiten zu kapseln, wie beispielsweise CommPorts mit vielen HANDLEs etc . Interna nach aussen geben, bedeutet ja gerade Abhaengigkeiten auf Implementationsdetails zuzulassen.



  • Skym0sh0 schrieb:

    // Foo.h
    class HiddenFoo;
    
    class Foo
    {
    	std::unique_ptr<HiddenFoo> m_foo;
    	
    public:
    	Foo();
    	
    	Typed getBar() const; // dieses Typed
    };
    
    // Foo.cpp
    #include "HiddenFoo.h"
    
    Foo::Foo()
    		: m_foo(new HiddenFoo)
    	{}
    
    Typed Foo::getBar() const // dieses Typed
    	{
    		return this->m_foo->getBar();
    	}
    

    So schonmal gar nicht. Das Klassen-Template unique_ptr<T> erlauibt zwar unvollständige Typen T im Allgemeinen, aber der Default-Deleter will dort, wo er instantiiert wird, einen vollständigen Typen haben. Und der wird bei reset, operator= und dem Destruktor von unique_ptr<T> ja benötigt. Deklarierst du also den Destruktor nicht im Header, wird er ggf on-the-fly inline an einer Stelle generiert, wo T noch unvollständig ist. Der Destruktor will dann auch operator() des Default-Deleters instantiiert haben und dann knallts. Ich würde von einer guten Implementierung erwarten, dass so ein Fehler erkannt werden kann ... und dann die Compilierung mit einer Fehlermeldung endet.

    Skym0sh0 schrieb:

    [...] aber ich habe in der weggekapselten Klasse eine komplexeres Typedef [...] Und dieses brauche ich in der PIMPL-Klasse. Aber wie mache ich das dort sichtbar ohne das PIMPL zu entfernen?

    Du packst diesen typedef irgendwie in den Header rein.



  • Das der Destruktor in die CPP muss sowie die Regel der Großen Drei eingehalten werden muss, weiss ich, das habe ich auch gemacht. Das soll jetzt auch nicht Thema sein hier, denn es vergrößert das Beispiel nur immens und bringt keinen semantischen Mehrwert...



  • knivil schrieb:

    Kompilierzeit verringern

    Das ist heute kein Problem.

    oh doch, wenn die Projekte groß genug werden...

    ein kompletter Clean Build unserer Solution dauert fast eine halbe Stunde... das übernimmt zum Glück der nächtliche Buildserver. Aber bei Änderungen an zentralen Komponenten kann es schonmal 5-10 Minuten dauern, bis das Ding startet.



  • Ich habe nicht gesagt, dass es nicht dauert. Ich habe nur gesagt, dass das Problem nicht besteht, weil es anders geloest wird. Auch wird wohl kaum jemand nach dem Trial & Error Prinzip zentrale Komponenten aendern.



  • Skym0sh0 schrieb:

    Hauptsächlich weil ich meine Compilezeit runterdrehen will und das äussere Interface klein bleiben soll.

    Hab ich mir gleich gedacht, nachdem ich Deine Deutsch verstanden hatte. Wir kommen der Sache näher.
    Wenn es um komplexte Typem wie angegeben handelt, dann geht das nicht, vermute ich. Wenn es nur darum geht, die <windows.h> loszuwerden, dann geht das sogar ohgne pimpl viel besser.
    Wobei Rückgabetypen auch bloß geforwarded sein können. Verträgt sich aber weniger mit Templates.
    Ich benutze fast nie pimpl, insbesondere nicht, um compilezeit zu sparen.

    Ach, ich verwende es nicht, um was zu verstecken, sondern (extrem selten) um Laufzeitpolymorphie zu haben, ohne Zeiger oder Referenzen zu sehen. Das Verstecken-Können ist dann nur zufällig ein netter Bonus.



  • volkard schrieb:

    Ich benutze fast nue pimpl, insbesondere nicht, um compilezeit zu sparen.

    Nie oder nur?



  • Nathan schrieb:

    volkard schrieb:

    Ich benutze fast nue pimpl, insbesondere nicht, um compilezeit zu sparen.

    Nie oder nur?

    nie



  • volkard schrieb:

    Wenn es nur darum geht, die <windows.h> loszuwerden, dann geht das sogar ohgne pimpl viel besser.

    Wie? 🙂



  • cooky451 schrieb:

    volkard schrieb:

    Wenn es nur darum geht, die <windows.h> loszuwerden, dann geht das sogar ohgne pimpl viel besser.

    Wie? 🙂

    <winforward.h>

    typedef void* HANDLE;
    ...
    

    <winforward.cpp>

    #include <windows.h>
    #include <winforward.h>
    
    static_assert<same_type<void*,HANDLE>>;
    ...
    


  • Ja.. und wie rufst du jetzt CreateWindow etc. auf? Ist ja dann auch so eine Art pimpl, nur halt ohne new. Und wenn man noch mehr will, dann muss man das auch alles im Header typedeffen. Und dann ist es auch nicht als plattformunabhängige Kapselung geeignet, weil die typedefs entsprechend angepasst werden müssten. Ne, da bleibe ich lieber bei pimpl. 🤡



  • cooky451 schrieb:

    Ja.. und wie rufst du jetzt CreateWindow etc. auf?´

    Wer so fette Brocken aufruft, darf im Allgemeinen sogar die <windows.h> höchstselbst inkludieren.
    Mir geht es darum, daß die tausend Helfer-Klassen File, Event, Semaphore, FileMapping, sowie einige Helfer-Funktionen wie sleep oder set dadurch plattformunabhängig werden. daß ich

    typedef void* os::FileHandle;
    

    mache, bzw unter linux int statt void*, und ich FileHandle benutze. Dadurch brauche ich kein pimpl, was da wirklich übertrieben langsam wäre.

    cooky451 schrieb:

    Ist ja dann auch so eine Art pimpl, nur halt ohne new. Und wenn man noch mehr will, dann muss man das auch alles im Header typedeffen. Und dann ist es auch nicht als plattformunabhängige Kapselung geeignet, weil die typedefs entsprechend angepasst werden müssten. Ne, da bleibe ich lieber bei pimpl. 🤡

    Es ist absolut geeignet für Plattformabhängigkeit wegmachen und gleichzeitig Compilezeit zu sparen, wenn man nicht auf HANDLE und so geht, sondern auf FileHandle, Socket, Event, auf die Begriffe, die die Betriebssysteme gemeinsam haben.


Anmelden zum Antworten