entledigen Sie einfach C ++ Anruf vollständig

8

Ich versuche eine Protokollierung zu implementieren, die keinen Overhead erzeugt, wenn sie nicht benötigt wird (d. h. es sollte überhaupt kein Methodenaufruf durchgeführt werden). Ich möchte keinen Overhead, weil es Code mit niedriger Latenz ist. Ich habe gerade #define ENABLE_LOGS zu meiner Header-Klasse hinzugefügt und jetzt sieht es so aus (du kannst Details ignorieren)

%Vor%

Jedes Mal, wenn ich eine Methode verwenden muss, sollte ich es so umgeben:

%Vor%

Es ist Fehler-phrone (ich kann vergessen zu umgeben) und macht den Code schmutzig. Kann ich meinen Code irgendwie reparieren, um #ifdef nicht jedes Mal zu verwenden?

In C # mag ich bedingt ich denke, ich brauche so etwas für C ++.

    
javapowered 15.07.2013, 21:07
quelle

5 Antworten

7

Es gibt einen Weg (wie es llvm macht), dies mit Makros zu tun.

%Vor%

Benutze es dann als:

%Vor%     
A. K. 15.07.2013, 21:12
quelle
13

Zunächst würde es Sinn machen, nachzusehen, was da draußen schon los ist. Dies ist ein häufiges Problem und viele Leute werden es schon früher gelöst haben. Siehe z. B. stackoverflow question C ++ - Protokollierungs-Framework-Vorschläge und Dr Dobbs Ein hoch konfigurierbares Protokollierungs-Framework in C ++ .

Wenn Sie Ihre eigenen rollen, sollten Sie einige gute Ideen davon bekommen, dies getan zu haben. Es gibt verschiedene Ansätze, die ich in der Vergangenheit angewendet habe. Eine besteht darin, die Anweisung selbst bedingt zu definieren

%Vor%

Ein anderer Ansatz besteht darin, die Protokollierungsklasse selbst bedingt zu definieren. Die nicht protokollierende Version enthält alles als leere Anweisungen, und Sie sind darauf angewiesen, dass der Compiler alles optimiert.

%Vor%

Sie könnten Ihre Logger -Implementierung für ENABLE_LOGS in eine cpp-Datei unter Kontrolle des Makros setzen. Ein Problem bei diesem Ansatz besteht darin, dass Sie sicher sein sollten, die Schnittstelle so zu definieren, dass der Compiler alles optimieren kann. Verwenden Sie beispielsweise einen C-String-Parametertyp ( const char* ). In jedem Fall ist const std::string& besser als std::string (letzteres stellt sicher, dass es bei jedem Anruf eine Zeichenkette gibt).

Wenn Sie sich für den ersten Ansatz entscheiden, sollten Sie schließlich alles in do() { ... } while(0) kapseln, um sicherzustellen, dass Sie kein bizarres Verhalten bekommen, wenn Sie Ihr Makro verwenden, wo eine zusammengesetzte Anweisung erwartet werden könnte.

    
TooTone 15.07.2013 21:19
quelle
3

Was ich oft sehe, ist die Verwendung der # define, um die Log-Aufrufe zu definieren, zB:

%Vor%

Aber Sie möchten die Definitionen in einen Block einfügen, der Ihre Protokollierung aktiviert oder deaktiviert:

%Vor%

Sie können LOG_DEBUG überall in Ihrem Code aufrufen. Wenn die Protokollierung deaktiviert ist, endet der Aufruf von LOG_DEBUG als leere Zeile in Ihrem endgültigen Code.

    
Lochemage 15.07.2013 21:13
quelle
0

Ein schöner alter Trick ist:

%Vor%

Dann der Code:

%Vor%

wird erweitert zu:

%Vor%

das macht das Protokoll. Oder:

%Vor%

das macht absolut nichts. Es evaluiert nicht einmal die Funktionsargumente !!!

Der Trick ist, dass die erste Version das Komma als Argumenttrennzeichen in einem Funktionsaufruf verwendet. In der zweiten Version ist es jedoch ein unbewerteter Komma-Operator.

Einige Compiler geben jedoch falsche Warnungen über nicht erreichbaren Code.

    
rodrigo 17.07.2013 19:37
quelle
0

Sie könnten #ifdef in den Rumpf der einzelnen Funktionen einfügen. Dies vermeidet das Codeduplikationsproblem in TooTones Antwort.

Beispiel:

%Vor%

Wenn ENABLE_LOGS nicht definiert ist, macht diese Funktion nichts. Was ich vorschlagen würde ist, dass Sie eine const char* anstelle von std::string an diese Methode übergeben. Wenn also ENABLE_LOGS nicht definiert ist, müssen Sie sich nicht darauf verlassen, dass der Compiler keine redundanten std::string -Objekte erstellt.

    
Zeenobit 17.07.2013 21:00
quelle

Tags und Links