einsetzen member vs getter



  • Vielleicht komischer Titel, aber die getter-Methoden geben ja die bestimmte membervariable zurück?

    Jetzt habe ich versucht, konsequent alle im Projekt vorhandenen Klassen die member-aufrufe durch die entsprechenden getter zu ersetzen. EDIT: in den Klassen-Methoden.
    Komplexe Typen mit

    const Typ& get() const;
    

    Jedoch habe ich jetzt das Phänomen, das der ausgeführte Code deutlich sichtbar langsamer geworden ist.
    Kann das an diesen Änderungen liegen oder sollte ich ne längerer Pause machen, oder?



  • Wenn die getter nicht inline sind, sondern tatsächlich als Funktionsaufruf ausgeführt werden, macht sich das sicher bemerkbar.



  • Aha, danke. Um Missverständnisse zu vermeiden, ein kleines Beispiel

    class C
    {
    public:
        void foo() const;
    private
        int v;
        int getV() const;
    };
    
    //entweder inline
    int C::getV() const
    {
        return v;
    }
    
    void C::foo() const
    {
        int x = v * 5; //oder so
        int x = getV() * 5; //wenn inline
    }
    

    Ist das so gemeint?



  • So wie es da steht wird der Compiler die Funktion inline ausführen (zumindest wenn der Optimizer eingeschaltet wurde).

    Die Verwendung von getter/setter in Memberfunktionen ist allerdings fragwürdig.

    Naja, eigentlich sind getter/setter an sich schon fragwürdig ...



  • @manni66 sagte in einsetzen member vs getter:

    So wie es da steht wird der Compiler die Funktion inline ausführen (zumindest wenn der Optimizer eingeschaltet wurde).

    Ich müsste sie direkt inline erklären, sollte aber nur zur Anschaung dienen.

    Die Verwendung von getter/setter in Memberfunktionen ist allerdings fragwürdig.

    Das nehme ich mal einfach so mit...

    Naja, eigentlich sind getter/setter an sich schon fragwürdig ...

    aber könntest Du das näher erläutern 🙂


  • Mod

    @lemon03 sagte in einsetzen member vs getter:

    @manni66 sagte in einsetzen member vs getter:

    So wie es da steht wird der Compiler die Funktion inline ausführen (zumindest wenn der Optimizer eingeschaltet wurde).

    Ich müsste sie direkt inline erklären, sollte aber nur zur Anschaung dienen.

    Wichtiger ist die Frage: Mit welchen Optimierungen compilierst du? Niemanden interessiert es, wie schnell oder langsam unoptimierter Code läuft. Dies ist eigentlich eine recht einfache Optimierung für jeden Compiler, daher liegt der Verdacht nahe, dass du keine Optimierungen aktiviert hast.

    Die Optimierung kann aber schwer werden, wenn die Funktionen in einer separaten Übersetzungseinheit definiert werden (anstatt inline im Header). In dem Fall muss man die Optimierungen zur Link-Zeit durchführen. Das ist für moderne Compiler auch kein Hexenwerk mehr, aber man muss eventuell ein bisschen mit den Einstellungen spielen, um das zu aktivieren, weil das über die Standardoptimierungsschalter hinaus geht.

    Die Verwendung von getter/setter in Memberfunktionen ist allerdings fragwürdig.

    Das nehme ich mal einfach so mit...

    Naja, eigentlich sind getter/setter an sich schon fragwürdig ...

    aber könntest Du das näher erläutern 🙂

    Allgemein trennt man gerne zwischen Klassen, die wirklich etwas tun, und Klassen, die einfach nur Daten halten. Bei einfachen Datenhaltern ist man normalerweise gut beraten, einfach nur ein struct mit public-Zugriff auf alle Daten zu machen. Bei Klassen, die wirklich etwas tun und irgendeinen für diese Funktion wichtigen internen Zustand haben, sollte es hingegen eigentlich nie notwendig sein, diesen Zustand explizit zu ändern. Die Zustandsänderungen erfolgen dort indirekt über die Funktionen der Klasse, abgekapselt vom Anwender. Ein Getter/Setter deutet darauf hin, dass man einen Mischzustand hat, wo man sowohl einen internen Zustand hat, der irgendwie verbergenswert ist, aber gleichzeitig diesen über die Getter/Setter vor aller Welt entblößt.

    PS: Ich habe vergessen, zu erklären, warum man gerne Klassen auf diese Weise trennt. Eine genaue Erklärung würde sehr weit führen, aber die Kurzfassung ist, dass man sein Programm damit deutlich(!) besser wartbar und erweiterbar macht.



  • Ok, ich denke, im Großen habe ich das verstanden und wenn ich es richtig verstanden habe, mache ich es eigentlich auch so. Bei auf meine drei Hauptklassen, benutze ich getter sehr wenig und nur wenn ich sie auch brauche, (edit:) setter eigentlich gar nicht. Aber bei mir ist es, mühsam ernährt sich das Eichhörnchen... Dauert alles ne Weile.

    Zu den Optimierungen: Benutze ich unter gcc ständig und ohne Ausnahme:

    [-O3]
    [-fexpensive optimizations]
    Optimize fully (for speed) [-O3]

    Ich kann doch von ausgehen, das [-O3] besser optimiert als [-O2]?



  • @lemon03 sagte in einsetzen member vs getter:

    Ich kann doch von ausgehen, das [-O3] besser optimiert als [-O2]?

    Du kannst ausgehen von was du willst 😉

    -O3 optimiert aggressiver. Das Ergebnis ist dann oft auch schnellerer Code. Manchmal aber auch nicht. Speziell erzeugt -O3 z.T. recht grossen Code, der in Microbenchmarks dann oft schneller ist als was mit -O2 erzeugt wird, aber in echten, grossen Programmen manchmal zu ner Verschlechterung durch übermässiges Bashing des Instruction-Cache führt.

    Aber kümmer dich erstmal nicht darum. Sowohl -O2 als auch -O3 erzeugen guten Code der in den meisten Fällen völlig OK ist.

    ps:
    @lemon03 sagte in einsetzen member vs getter:

    Ok, ich denke, im Großen habe ich das verstanden und wenn ich es richtig verstanden habe, mache ich es eigentlich auch so.

    Wenn du wirklich (wie in deinem Beispiel) private getter verwendest die einfach nur Referenzen auf Membervariablen zurückgeben, dann bezweifle ich dass du es "verstanden hast und auch so machst".



  • Wie gesagt, mühsam ernährt sich das Einhörnchen. Ein Beispiel meiner aktuellsten Klasse:

    class Plasma
    {
    public:
    
        Plasma( const Charset& charset,
                int width, int height, double s ) : plasma_width( width ),
                                                    plasma_height( height ),
                                                    color_range( static_cast<int>( charset.getSize() / 2 ) ),
                                                    scaler( s ),
                                                    col_palette( charset.getChars() )
        {
            generatePlasma();
        }
    
        int getWidth() const; //benötige ich, um zB später zB mehrere Plasmas 
        int getHeight() const; //nebeneinander zu zeigen
        void paint( const PaintArea&, int, int, int, int, int ) const;
    
    private:
    
        int plasma_width  = 0;
        int plasma_height = 0;
        int color_range = 0;
        double scaler = 0;
        std::vector<std::vector<std::size_t>> plasma;
        std::vector<Char> col_palette;
    
       void generatePlasma();
    
        //noch aus meinen getter-Versuchen
        /*int getColRange() const;
        double getScaler() const;
        const std::vector<std::vector<std::size_t>>& getPlasma() const;
        const std::vector<Char>& getColPalette() const;*/
    };
    

    Wie ist das hier mit den Referenzen auf Membervariablen gemeint?



  • @lemon03 sagte in einsetzen member vs getter:

    Wie ist das hier mit den Referenzen auf Membervariablen gemeint?

    Sowas wie die auskommentierten Funktionen getPlasma bzw. getColPalette hatte ich gemeint. Wenn du das eh nicht so machst sondern nur mal (warum auch immer) probiert hattest, dann ist das eh OK. Weil das halt keinen Sinn macht.



  • Danke. Fein, das das geklärt ist 🙂



  • @seppj sagte in einsetzen member vs getter:

    Das ist für moderne Compiler auch kein Hexenwerk mehr, aber man muss eventuell ein bisschen mit den Einstellungen spielen, um das zu aktivieren, weil das über die Standardoptimierungsschalter hinaus geht.

    Welche Einstellungen sind denn da zu ändern? Wenn du einen Link oder Kurzbeschreibung hättest wäre super.
    Bin immer davon ausgegangen, dass das optimiert wird.


  • Mod

    @jockelx sagte in einsetzen member vs getter:

    @seppj sagte in einsetzen member vs getter:

    Das ist für moderne Compiler auch kein Hexenwerk mehr, aber man muss eventuell ein bisschen mit den Einstellungen spielen, um das zu aktivieren, weil das über die Standardoptimierungsschalter hinaus geht.

    Welche Einstellungen sind denn da zu ändern? Wenn du einen Link oder Kurzbeschreibung hättest wäre super.
    Bin immer davon ausgegangen, dass das optimiert wird.

    Kommt halt auf den Compiler/Linker an. Auf jeden Fall habe ich es noch nirgendwo standardmäßig gesehen. Ist meistens auch gar nicht nötig, da man die guten Kandidaten für Inlining normalerweise sowieso im Header inline implementieren sollte (oder halt direkt in der Klassendefinition, wodurch sie implizit auch inline sind). Darum heißt das Schlüsselwort schließlich so 🙂

    Das Stichwort zur Suche nach Dokumentation ist link time optimization.



  • @Jockelx Für GCC ist das hier beschrieben: https://gcc.gnu.org/wiki/LinkTimeOptimization
    Bei Visual Studio heisst es "Whole Program Optimization": https://msdn.microsoft.com/en-us/library/0zza0de8.aspx



  • @Hustbaer: Danke für den Link; schau ich mir mal an.

    @SeppJ : Ja, sollte... vorgegebener Coding-style sagt aber manchmal was anderes...;-)


Log in to reply