Aufruf von Methoden zählen



  • Hallöchen 🙂

    Mein Vorhaben: ich will die Aufrufe von Funktionen zählen, d.h. so ne Art static Variable für jede Methode haben, die beim Aufruf der Methode um einen Wert inkrementiert und beim verlassen der Methode um einen Wert dekrementiert wird. Hinzu kommt noch, daß ich das ganze mit der Hilfe von Präcompiler-Makros erledigen will (damit ich diese Methodik ggf. auch ausschalten kann).
    Mein Problem: Ich kann zwar eine static Variable in jeder Methode initialisieren, und diese dann erhöhen, jedoch ist mir das ganze zu unsauber. Nun wollte ich mir eine kleine Klasse schreiben, die im Konstruktor diese Variable erhöht und im Destruktor diese Variable vermindert. Nur wie genau stelle ich dies nun an? Wenn ich eine Klasse schreibe und deren Zählvariable als static deklariere, greife ich doch von allen instantiierten Objekten dieser Klasse auf ein und die selbe Zählvariable zu, oder nicht? Demzufolge würde der Zähler nicht mehr auf eine Methode bezogen sein, sondern auf alle (was mir nicht hilft).
    Kann ich die Klasse als static deklarieren? Wenn ja, wie würde sich dann das Verhalten auf die restlichen Variablen innerhalb der Klasse auswirken?

    gedacht ist in etwa folgendes:

    void A() {
      ...
      static helpClass help;
    }
    
    void B() {
      ...
      static helpClass help;
    }
    
    class helpClass {
    
    public:
       helpClass() {
         counter++;
       }
    
       ~helpClass() {
         counter--;
       }
    
    private:
       int counter;
    }
    

    ginge das so? Er soll halt A und B separat zählen.

    mfg maddin



  • Der "counter" in der Klasse ist so schon richtig bei dir, aber der Konstruktor und Destruktor machen nicht das, was du haben möchtest.
    Überleg dir mal wieso...



  • Ich mutmaße jetzt einmal, daß der Konstruktor und der Destruktor je nur EINMAL aufgerufen werden, richtig? Demzufolge würde bei einem zweiten Durchlauf dieser Methode weder der Konstruktor noch der De~ ausgeführt (also meine Variable nicht gezählt werden).

    ähnlich als würde ich folgendes machen:

    void A {
      static int counter = 0; // wird nur einmal ausgeführt
      ...
      counter ++;
    }
    

    richtig?

    mfg maddin



  • Ja, ersteres stimmt, aber der folgende Code ist richtig:

    void A()
    {
      static int counter = 0; // Initialisierung wird nur einmal ausgeführt
      ...
      counter ++;
    }
    

    Wenn du eine Klasse benutzen willst, so mußt du dann auch jedes mal eine Methode oder Operator davon aufrufen, z.B.

    void A() {
      static helpClass help;
    
      help++;
    }
    

    d.h. gewonnen hast du jetzt gegenüber der obigen Counter-Variablen nichts.
    Du müßtest dann im Konstruktor der Klasse aber noch die Counter-Variable auf 0 initalisieren (hattest du in der helpClass vergessen).

    Trotzdem kannst du dies so benutzen und per Präprozessor die Klassenmethoden dann notfalls auskommentieren (leere Klassen bzw. Methoden erzeugen, welche der Compiler dann im Release-Build wegoptimiert).

    Nun bleibt dir nur noch die Übung den operator ++ der Klasse 'helpClass' zu definieren...



  • Warum willst du das machen? Wenn du wissen willst wie oft ein Teil deines Programms aufgerufen wird, dann würd ich dir zu nem Profiler raten.



  • Wir programmieren derzeit im Rahmen unseres Studiums ein kleines eigenes Betriebssystem (CoStubs, angelehnt an OoStubs von der Uni Magdeburg). Nun sind wir bereits beim Thema threads und Interrupts und es wird nun eine Methode mehrfach aufgerufen, obwohl sie das gar nicht dürfte. Der Einbau meiner kleinen Idee hier soll uns ermöglichen, unser Ding zumindest für diesen Fall zu debuggen.
    Da wir beim Compilieren ein bootdisk Image erstellen und das Ding in bochs laufen lassen haben wir kaum Debug-Möglichkeiten. (das remote Debugging funktioniert nur begrenzt und nicht wirklich zufriedenstellend, und jetzt mit Interrupts ist es noch schwieriger geworden).

    mfg Maddin



  • Das kannste Dir auch ein bißchen einfacher machen. Zunächst bauste Dir mal ein globales Objekt oder Singleton, das bekommt entweder ne map<string, int> oder aber auch nen stack<string>.

    Dann bauste Dir ein Objekt:

    class CallStackUpdater
    {
    public:
      CallStackUpdater(std::string const& str)
      {
        // hier das globale Objekt holen und entweder den Counter von str erhöhen
        // oder den übergebenen string auf den stack dort legen 
      }
    
      ~CallStackUpdater()
      {
        // counter im globalen Objekt runterzählen bzw. letztes Stackelement runternehmen
      }
    
      // besser Implementierungen verbieten Copy + Assignment etc.
    }
    

    Jetzt könntest Du am Anfang der Funktion schreiben:

    void eineFunktion() 
    {
      CallStackUpdater meinUpdater("eineFunktion");
    
      // Rest des Codes
    }
    

    Da das noch nicht so schön ist kannste Dir vielleicht ein Makro bauen, daß das für Dich tut. Insbesondere bieten einige Compiler die Möglichkeit mit __FUNC__ oder ähnlichem auf den Namen der aktuellen Funktion zuzugreifen. Damit müßtest Du nur noch am Anfang aller Funktionen zum Beispiel PUSH_FUNCTION(); hinschreiben.

    MfG Jester


Anmelden zum Antworten