Neues C++ Tool: Header Hero





  • Ist ja nur wieder das pimpl pattern... nichts neues



  • pimpl schrieb:

    Ist ja nur wieder das pimpl pattern... nichts neues

    Ja, aber ein Tool dass misst welcher Header am meisten zur Compiletime beträgt ist keine schlechte Idee.



  • Mir gefällt das Tool auch sehr gut. Bei meinen eigenen Programmen habe ich einen "BlowUp"-Faktor von ca. 2-3 (aber ich hatte da auch noch nie Kompilierzeitprobleme).
    Ich hätte das Tool aber gerne mal vor einigen Jahren eingesetzt, wo wir bei einem großen Spiele-Projekt Kompilierzeiten von ca. 20 Minuten hatten (und das trotz IncrediBuild).



  • pimpl schrieb:

    Ist ja nur wieder das pimpl pattern... nichts neues

    Ist zwar offtopic, da es aber angesprochen wurde: Nutzt ihr pimpl immer noch häufig?
    Der wichtigste Grund dürfte ja die Reduzierung der Kompilierzeit sein, aber mit den heutigen Rechnern erscheint mir das doch ein wenig überholt.

    Ich sitze hier an einem i7 mit massig RAM, das aktuelle Projekt bestehend aus mehr als einem Dutzend Teilprojekten wird innerhalb kürzester Zeit komplett kompiliert, bei Änderungen in Quelldateien "spürt" man dank vorkompilierter Header diesen Vorgang eigentlich gar nicht.

    Pimpls wurden in diesem Projekt so gut wie gar nicht verwendet (und ja, mit meinem Uraltnotebook mit mobilem Athlonprozessor dauert es schon eine kleine Ewigkeit).

    Daher die Frage, ist das pimpl Idiom mittlerweile obsolet?



  • Ich finde Pimpl eher gut im Implementierungsdetails zu verstecken.
    Die Laufzeit zu erhöhen nur um Compilezeit zu sparen ist doch Käse.



  • Wieso?
    Nach der 80/20 Regel kann man an 80% der Stellen ruhig mal etwas ein paar Prozent langsamer machen, ohne dass es allzusehr stört.
    Wenn das Ding dafür dann 3x so schnell compiliert, wieso nicht?



  • Kein Pimpler schrieb:

    Daher die Frage, ist das pimpl Idiom mittlerweile obsolet?

    Pimpl zum Sparen von Compilezeit war schon immer eine Schnapsidee.
    Pimpl zum geheimhalten der Implementierung war schon immer eine Schnapsidee.



  • Das begründe mal.



  • Tyrdal schrieb:

    Das begründe mal.

    Muß ich nicht. Ich mußte auch nicht begründen, warum Struktogramme nichts bringen und warum ungarische Notation nichts bringt und warum UML als Planungswerkzeug nichts taugt. Ich lasse mich nicht anstecken, gebe gelegentlich ein lästerliches Statement ab, und warte, bis der Hype von selbst verschwindet.



  • Stimmt du mußt nicht, aber so bist du im Moment ein Troll.



  • Ein Troll der meiner Meinung nach Recht hat. 😉
    Man muss nicht für alles eine Begründung liefern, wenn die Begründung klar auf der Hand liegt.



  • Ich sehe die Begründung nicht. Bitte um eine Erklärung.



  • Das langt für mich :

    More work for the implementor.
    Doesn't work for 'protected' members where access by subclasses is required.
    Somewhat harder to read code, since some information is no longer in the header file.
    Run-time performance is slightly compromised due to the pointer indirection, especially if function calls are virtual (branch prediction for indirect branches is generally poor).



  • Man kann damit unportablen Code "verstecken", sodass zum Beispiel der Header nicht den globalen Namespace mit der WinAPI verseucht. Bei solchen Dingen spielt der Overhead dann auch gar keine Rolle, weil die darunterliegenden Aufrufe relativ teuer sind.

    //event.hpp
    
    struct Event
    {
    	Event();
    	~Event();
    	void set();
    	void wait();
    
    private:
    
    	struct EventImpl;
    
    	std::unique_ptr<EventImpl> m_impl;
    };
    
    //event.cpp
    
    #include "event.hpp"
    
    #ifdef _WIN32
    #include <Windows.h>
    
    struct Event::EventImpl
    {
    	HANDLE eventHandle;
    
    	EventImpl()
    		: eventHandle(::CreateEvent(NULL, FALSE, FALSE, NULL))
    	{
    	}
    
    	~EventImpl()
    	{
    		::CloseHandle(eventHandle);
    	}
    
    	void set()
    	{
    		::SetEvent(eventHandle);
    	}
    
    	void wait()
    	{
    		::WaitForSingleObject(eventHandle, INFINITE);
    	}
    };
    #endif
    
    Event::Event()
    	: m_impl(new EventImpl)
    {
    }
    
    Event::~Event()
    {
    }
    
    void Event::set()
    {
    	m_impl->set();
    }
    
    void Event::wait()
    {
    	m_impl->wait();
    }
    

    EDIT: wie immer ohne Gewähr



  • Mann, ist das schön wenn man in einer Sprache mit Modulen programmiert *troll-modus* 🤡



  • Man muß es nicht begründen, weil derjenige, der was Umständliches einführt, im Begründungszwang ist.

    Ich erfinde mal ein rosa unsichtbares Einhorn. Und dann kommt von mir nachgeschlagen, daß ich jeden, der das Einhorn ablehnt, ohne die Ablehnung zu begründen, ein Troll wäre. Das ist schlecht. Das machst Du aber gerade.

    Wenn Du Pimpl liebst, darfste es begründen.



  • TyRoXx schrieb:

    Man kann damit unportablen Code "verstecken", sodass zum Beispiel der Header nicht den globalen Namespace mit der WinAPI verseucht. Bei solchen Dingen spielt der Overhead dann auch gar keine Rolle, weil die darunterliegenden Aufrufe relativ teuer sind.

    //event.hpp
    
    struct Event
    {
    	Event();
    	~Event();
    	void set();
    	void wait();
    	
    private:
    
    	struct EventImpl;
    	
    	std::unique_ptr<EventImpl> m_impl;
    };
    
    //event.cpp
    
    #include "event.hpp"
    
    #ifdef _WIN32
    #include <Windows.h>
    
    struct Event::EventImpl
    {
    	HANDLE eventHandle;
    	
    	EventImpl()
    		: eventHandle(::CreateEvent(NULL, FALSE, FALSE, NULL))
    	{
    	}
    	
    	~EventImpl()
    	{
    		::CloseHandle(eventHandle);
    	}
    	
    	void set()
    	{
    		::SetEvent(eventHandle);
    	}
    	
    	void wait()
    	{
    		::WaitForSingleObject(eventHandle, INFINITE);
    	}
    };
    #endif
    
    Event::Event()
    	: m_impl(new EventImpl)
    {
    }
    
    Event::~Event()
    {
    }
    
    void Event::set()
    {
    	m_impl->set();
    }
    
    void Event::wait()
    {
    	m_impl->wait();
    }
    

    EDIT: wie immer ohne Gewähr

    Geht viel performanter und meiner Meinung nach auch einfacher, wenn man die WinAPI-Funktionen und -Typen plattformneutral verpackt. Pimpl wird hier mißbraucht. Vermutlich wie die Singhletons, die ebenfalls zu berühmt sind, und sich deswegen auch in unpassende Löcher stopfen.



  • volkard schrieb:

    TyRoXx schrieb:

    ...

    Geht viel performanter und meiner Meinung nach auch einfacher, wenn man die WinAPI-Funktionen und -Typen plattformneutral verpackt. Pimpl wird hier mißbraucht. Vermutlich wie die Singhletons, die ebenfalls zu berühmt sind, und sich deswegen auch in unpassende Löcher stopfen.

    Habe ich nicht genau das gemacht? Wie würdest du es denn viel performanter machen?



  • os/Windows.hpp

    namespace os{
    typedef void* Event;
    Event eventCreate();
    void eventClose(Event event);
    void eventSet(Event event);
    void eventWait(Event event);
    }//namespace os
    

    os/Windows.cpp

    #include <windows.h>
    #include <Windows.hpp>
    
    namespace os{
    static_assert(tmp::isSameType<Event,HANDLE>::value,"Type Mismatch");
    Event eventCreate(){
       return CreateEvent(NULL, FALSE, FALSE, NULL);
    }
    //usw
    }//namespace os
    

    Die Event-Klasse wird dann ganz herkömmlich gebaut, nur halt mit den plattformneutralen API-Namen.

    Zusatzkosten: Nur ein Funktionsaufruf pro API-Aufruf. Und selbst das kann man leicht ifdeffen, so daß im Releasecode wieder lange Compilezeit und zero Laufzeitoverhead hat. Pimpl kann man nicht leicht ifdeffen.


Anmelden zum Antworten