2013-03-20 10 views
8

Ich arbeite an einer Protokollierung/Tracing-Einheit (und bitte nicht zeigen auf bestehende, dies ist für die Erfahrung so viel wie für das Ergebnis).Anonyme Objekte auf dem Stapel, in C++?

Um eine Laufzeitaufruf-Stack-Trace zu erhalten, ist die Idee, eine TraceObject Instanz zu erstellen, zuerst eine Funktion eingegeben wird, die die Informationen der aktuellen Klasse und Funktion enthält. Etwas ähnlich:

TraceObject to("MyClass", "myClassFunction"); 

Konstruktor TraceObjectthis auf einer Pro-Thread-Stack drückt, springt der Destruktor ihn wieder. Der Stapel kann somit für den Aufrufstapel abgefragt werden.

Ich habe das funktioniert zur Zufriedenheit. Allerdings gibt es einen kleinen Schnatz: Das Objekt to. Es wird, von Entwurf, nie mit diesem Namen bezeichnet werden. Daher muss keinen einen Namen haben, am allerwenigsten einer, der mit den vom Client verwendeten Bezeichnern kollidieren könnte (oder im Fall von _ Präfix die Implementierung).

tl; dr

Ist es möglich, ein anonymen, nicht-temporäres Objekt auf dem Stapel zu erstellen (dh eine, die bis der Funktion zurückkehrt leben, aber nicht über eine Kennung), und wenn ja, wie würde es gemacht werden?

+3

Ich glaube nicht, dass es möglich ist, streng, aber mit einem Makro und einem obskuren Namen, können Sie das gleiche erreichen. Gibt es einen triftigen Grund, warum Sie es brauchen, um namenlos zu sein oder ist es eher ein "es ist nicht wirklich erforderlich". –

+0

@KarthikT: Ja, ein Wrapper-Makro war die allgemeine Idee. Ich habe mich nur gefragt, ob ich "obskur" beseitigen und "unsichtbar" erreichen könnte. – DevSolar

+0

@Karthik T genau, das ist auch, wie Boost-Protokoll macht es so meine Vermutung ist: es gibt keinen anderen Weg – stijn

Antwort

5

Nr

Es gibt anonyme Objekte in C++, Provisorien, die die Ergebnisse der Ausdrücke sind jedoch nur sie in Zusammenhang mit der Aussage leben sie in sind.

Wenn Sie tatsächlich versuchen, ein anonymes Objekt deklarieren, verwirren Sie den Parser und er denkt, Sie deklarieren ... eine Funktion!


Aber dann, ist es notwendig?

Wenn Sie akzeptieren, Makros zu verwenden, um die TraceObject tatsächlich zu deklarieren, ist es so einfach, ein Makro für jede Ablaufverfolgung zu verwenden; und somit die Klasse und Funktion dort bereitstellen. Mit __func__ oder gleichwertig können Sie den Klassennamen und den Funktionsnamen extrahieren (Bit des benötigten String-Parsings, abhängig vom Compiler) und von dort aus arbeiten.

Und natürlich würden Sie sowieso ein Makro für jede Spur verwenden, weil Sie wahrscheinlich den Dateinamen und die Zeilennummer möchten!

+0

können Sie die Lebenszeit des temporären Objekts mit const referenzieren, aber const referenz selbst ist ein anderer Name des temporären Objekts: const T & r = T(); – AnatolyS

+0

@AnatolyS: const-Verweis oder rvalue-Verweis (in C++ 11), aber ja, wie Sie bemerkt haben, führt es trotzdem eine Kennung ein. –

+0

Ich mag den '__func__' Weg nicht, da seine Implementierung definiert ist. Aber Sie bekommen das Häkchen, um die Frage tatsächlich zu beantworten, ob anonyme Objekte möglich sind ("Nein"). ;-) – DevSolar

3

Wie ich in meinem Kommentar sage, können eingeschränkte anonyme Variablen nicht verwendet werden.

#define BEGIN_LOG TraceObject abcdefghij("", __func__); 

void Function(){ 
    BEGIN_LOG; 

    //bla bla 

} 

Dies sollte es tun, vorausgesetzt, es gibt einen Compiler-Makro, um Klassenname zu erhalten.

Edit: Kein Glück mit einer einfachen Möglichkeit, Klassennamen zu bekommen, müssen Sie etwas tun, was bei Class name macro vorgeschlagen wird. Oder machen Sie einfach mit __FILE__.

Bearbeiten: Sie können versuchen, __func__ und __FUNCTION__ um zu sehen, ob eine oder beide funktionieren wie Sie möchten. Weder ist C++ - Standard angegeben.

+0

AFAIK, '__func__' ist nicht im C++ - Standard, nur C. Oder hat sich das mit C++ 11 geändert? – DevSolar

+0

@DevSolar ist weder __FUNCTION__ ich glaube? Irgendeine Idee, die besser unterstützt wird? –

1

Einige Zeilennummer Zeug:

#define XPASTE(arg1, arg2) PASTEX(arg1, arg2) 
#define PASTEX(arg1, arg2) arg1 ## arg2 
#define TRACELOG() \ 
      TraceObject XPASTE(trace_object, __LINE__) 
+0

Nicht viel Verschleierung durch das Hinzufügen von '__LINE__', aber zumindest vermeiden Sie" Schatten "Warnungen, wenn ein zweites' TraceObject' erstellt wird. .. – DevSolar