Verständnisfrage Statische Funktionen



  • Hallo

    wenn ich in meiner Klasse eine Funktion statisch deklariere, dann kann diese von überall aufgerufen werden und insbesondere sind sie einmalig im Sinne, dass nicht bei jedem Aufruf ein Objekt erzeugt wird.

    Kann man daraus schließen, dass statische Funktionen automatisch das Programm performanter machen?

    Danke und Grüße



  • Seit wann wird bei jedem Aufruf einer Memberfunktion ein Objekt erzeugt?



  • Es wird einfach ein Parameter weniger an die Memberfunktion übergeben.



  • Hallo

    Eure beiden Antworten lassen mich zu dem Schluss kommen, dass ich immer noch nicht verstanden habe was es mit static aufsich hat, obwohl ich in mehreren Büchern jede Seite dazu studiert habe. So deprimierend... 😞

    @Th69
    Wie meinst du das, dass ein Paameter weniger übergeben wird?

    @manni66
    Ich dachte dem wäre so. Könnte man es so formulieren: Auf eine statische Memberfunktion kann zur gesamten Laufzeit zugegriffen werden, ohne dass bei jedem Aufruf eine Klasseninstanz nötig ist?

    Danke für die Hilfe

    Grüße





  • oh glaub mir das habe ich schon alles gelesen 😞



  • Statische Methoden können auch ohne einer Instanz der Klasse aufgerufen werden, haben dann aber nur Zugriff auf statische Methoden und Variablen der Klasse.



  • cpp_Jungspund schrieb:

    @Th69
    Wie meinst du das, dass ein Paameter weniger übergeben wird?

    Er meint wohl, dass der "unsichtbare" Parameter "this" bei statischen Methoden nicht existiert (und somit nicht übergeben wird), weil diese Methoden ohne Instanz der Klasse aufgerufen werden und es somit kein "this" geben kann.



  • cpp_Jungspund schrieb:

    oh glaub mir das habe ich schon alles gelesen 😞

    Du hast den Sinn von Klassen/Objekten einerseits und den von freien Funktionen (gegebenenfalls in Namespaces) andererseits nicht verstanden (siehe auch hier https://www.c-plusplus.net/forum/337865). Dementsprechend erschließt sich dir der Sinn von statischen Klassenfunktionen nicht.



  • @Übergeber: Ja, genau das meinte ich. Ich habe das nur hingeschrieben, da explizit nach Performance gefragt wurde, aber ich teile jetzt die Meinung von manni66, daß bei cpp_Jungspund noch generelle C++ Grundlagendefizite vorhanden sind.



  • Th69 schrieb:

    ich teile jetzt die Meinung von manni66, daß bei cpp_Jungspund noch generelle C++ Grundlagendefizite vorhanden sind.

    Ich glaub's auch... 😞 Werde weiter lernen und melde mich wieder.


  • Mod

    Falls du ein bisschen andere Sprachen kannst (z.B. C): Vielleicht hilft der Fakt, dass Klassen und Objekte in C++ nichts magisches sind. Sie sind nur rein grammatikalische Konstrukte; Abkürzungen für Dinge, die, wenn man sie komplett ausschreiben würde, ein bisschen umständlich wären; und sie bieten dem Compiler die Möglichkeit, Regeln zur Datenkapselung zu überprüfen. Das Resultat im Maschinencode ist aber in jedem Fall das gleiche, das man mit ein bisschen mehr Code auch in C (oder in C++ ohne Klassen) hätte schreiben können.

    class Foo
    {
      int i;
      double d;
    };
    

    Dies ist so erst einmal identisch zu

    struct Foo
    {
      int i;
      double d;
    };
    

    , außer dass der Compiler andere Regeln anwendet, wer auf die privaten Felder zugreifen darf und wer nicht (Zur Compilezeit! Im Maschinencode bleibt davon nichts übrig). Wenn so eine Klasse instantiiert wird, dann kommt exakt das gleiche Layout im Arbeitsspeicher heraus wie beim Struct.

    class Foo
    {
      int i;
      double d;
    public: 
      void bar(int j)
      {
        i = j;
      }
    };
    
    // ....
    Foo f;
    f.bar(123);
    

    Dies ist vom Resultat her wieder exakt identisch zu:

    struct Foo
    {
      int i;
      double d;
    };
    
    void foo_bar(Foo* this, int j)  // Wie exakt die Funktion heißt, ist nicht festgelegt
    {
        this->i = j;
    }
    
    // ....
    struct Foo f;
    foo_bar(&f, 123);
    

    Wieder sind die einzigen Unterschiede, dass der Compiler strenger prüfen kann, wer die Funktion wo und wie aufrufen darf; und dass in C++ etwas weniger Code nötig ist und vor allem der ganze Code, der sich bei jeder Memberfunktion wiederholen würde, entfällt. Wichtig mitzunehmen ist, dass die Memberfunktion auch nur eine ganz normale Funktion ist und das Klassenobjekt auch nur ein ganz normales Datenstruct ist und die große "Magie" ist nur, dass der Compiler versteckt den this-Zeiger einsetzt, wohingegen du so etwas in C bei jedem Aufruf selber hättest schreiben müssen.

    Somit kannst du dann auch ganz leicht static-Funktionen verstehen, das sind einfach Memberfunktionen ohne this-Zeiger; also im Prinzip eine ganz normale Funktion, die von der Namensgebung her mit der Klasse verknüpft ist:

    class Foo
    {
      int i;
      double d;
    public:
      static void bar(int j)
      {
        std::cout << "Foo " << j << '\n';
      }
    };
    
    // ....
    Foo::bar(123);
    

    ist nichts anderes als:

    struct Foo
    {
      int i;
      double d;
    };
    
    void foo_bar(int j)  // Wieder ist nicht festgelegt, wie die Funktion intern genau heißt.
    {
      std::cout << "Foo " << j << '\n';
    }
    
    // ....
    foo_bar(123);
    

    Keinerlei Zauberei.



  • Wow, vielen Dank für die Mühe SeppJ. Sobald ich heute Abend von der Arbeit komme guck ich mir das an 🙂



  • Hallo,

    mir ist gerade die gleichen Frage durch den Kopf geschossen.

    manni66 schrieb:

    Seit wann wird bei jedem Aufruf einer Memberfunktion ein Objekt erzeugt?

    naja:

    for(int i=0; i < size; ++i)
    {
      ClassName().function(i);
    }
    

    Okay, das Beispiel ist vielleicht etwas stark vereinfacht, aber es geht hier um die Performance Frage.

    for(int i=0; i < size; ++i)
    {
      ClassName::function(i);
    }
    

    was ist jetzt schneller?

    Rein vom Verständnis - was passiert beim Beispiel 1:
    Zuerst muss ein Konstruktor aufgerufen werden. Bei jedem Aufruf einer Funktion müssen alle lokalen Variablen auf den Stack abgelegt werden. Nach dem Zurückkommen aus dieser wieder geladen.
    Das instanzieren der Klasse reserviert Speicher.
    Erst danach wird die eigentliche Funktion ausgeführt.
    Im Anschluss wird der Destruktor ausgeführt. Heißt doch wieder Variablen auf den Stack ablegen und wieder laden.

    Die ersten beiden Schritte entfallen doch bei der Variante 2?
    Und der Destuktor muss auch nicht aufgerufen werden.

    Also rein von meiner Überlegung ist eine static Funktion schneller.

    Okay, in dem einfachen Beispiel hätte ich das erzeugen des Objekts außerhalb der for-Schleife gemacht und nur noch mit dem Objekt selbst in der Schleife gearbeitet. Das sparrt das ständige konstruieren und Zerstören des Objekts.


  • Mod

    So ein Schmarrn. Wenn du für jeden Aufruf der Funktion ein eigenes Objekt anlegst und zerstörst, dann hält dieses Objekt offensichtlich keinen relevanten Zustand, der erhalten werden soll. Was bedeutet, dass die Klasse nicht richtig designt ist. Dummfugbeispiel.

    Entweder muss der Objektzustand erhalten bleiben, dann braucht das Objekt auch nicht jedes Mal erzeugt und zerstört werden und es kommt alles auf einfachen Funktionsaufruf hinaus. Oder der Objektzustand muss nicht erhalten werden, dann kann die Funktion keine sinnvolle Memberfunktion des Objekts sein und hätte von vornherein static oder - weitaus wahrscheinlicher - eine freie Funktion sein sollen. Also wieder ein ganz normaler Funktionsaufruf.

    Weiß nicht, ob falsch verstanden, oder mit Absicht dummes Beispiel konstruiert, um Kontroverse zu erzeugen.

    PS: Das reine "reservieren" von Speicherplatz für Variablen auf dem Stack dauert so ziemlich ungefähr 0 Zeit.



  • @cpp_Jungspund: halte dich an SeppJs ausführliche erklärung.

    der einzige teil deiner frage, der noch kommentiert werden sollte:
    wenn du wirklich wissen willst, was "performanter" ist, dann musst du nachmessen.
    aber dann musst du auch zuerst wissen, was "performant" überhaupt heißt.

    in diesem fall ist die frage ungefähr so wie: ich habe eine funktion, die sortiert mir alle wörter in einer liste alphabetisch. außerdem hab ich auch eine funktion, die alle wörter nach länge sortiert. welche ist performanter?


Anmelden zum Antworten