69 Stimmen

Hat schon einmal jemand das Präprozessormakro __COUNTER__ verwendet?

El __COUNTER__ Symbol wird bereitgestellt von VC++ und GCC und ergibt bei jeder Verwendung einen zunehmenden nicht-negativen Integralwert.

Ich bin daran interessiert, zu erfahren, ob jemand es jemals benutzt hat, und ob es etwas ist, das es wert wäre, standardisiert zu werden?

67voto

__COUNTER__ ist überall dort nützlich, wo Sie einen eindeutigen Namen benötigen. Ich habe ihn ausgiebig für RAII-ähnliche Sperren und Stapel verwendet. Bedenken Sie:

struct TLock
{
  void Lock();
  void Unlock();
}
g_Lock1, g_Lock2;

struct TLockUse
{
  TLockUse( TLock &lock ):m_Lock(lock){ m_Lock.Lock(); }
  ~TLockUse(){ m_Lock.Unlock(); }

  TLock &m_Lock;
};

void DoSomething()
{
  TLockUse lock_use1( g_Lock1 );
  TLockUse lock_use2( g_Lock2 );
  // ...
}

Es wird mühsam, die verwendeten Sperren zu benennen, und kann sogar zu einer Fehlerquelle werden, wenn sie nicht alle am Anfang eines Blocks deklariert werden. Woher wissen Sie, ob Sie auf lock_use4 o lock_use11 ? Es ist auch unnötige Verschmutzung des Namensraums - ich brauche nie auf die Sperre verwenden Objekte mit Namen zu verweisen. Ich verwende also __COUNTER__ :

#define CONCAT_IMPL( x, y ) x##y
#define MACRO_CONCAT( x, y ) CONCAT_IMPL( x, y )
#define USE_LOCK( lock ) TLockUse MACRO_CONCAT( LockUse, __COUNTER__ )( lock )

void DoSomething2()
{
  USE_LOCK( g_Lock1 );
  USE_LOCK( g_Lock2 );
  // ...
}

Aber stören Sie sich nicht an der Tatsache, dass ich die Objekte Sperren genannt habe - jede Funktion, die in passenden Paaren aufgerufen werden muss, passt in dieses Muster. Es ist sogar möglich, dass Sie dieselbe "Sperre" in einem bestimmten Block mehrfach verwenden.

14voto

Michael Burr Punkte 320591

Ich habe es in einem Kompilierzeit-Assertion-Makro verwendet, damit das Makro einen Namen für ein Typedef erstellt, der eindeutig sein wird. Siehe

wenn Sie die blutigen Details wissen wollen.

13voto

JamieH Punkte 1217

Es wird in der xCover Codeabdeckungsbibliothek, um die Zeilen zu markieren, die bei der Ausführung durchlaufen werden, um diejenigen zu finden, die nicht abgedeckt sind.

13voto

Charlie Martin Punkte 106684

Ich habe es nie für etwas anderes als ein DEBUG-Makro verwendet. Es ist praktisch, sagen zu können

#define WAYPOINT \
    do { if(dbg) printf("At marker: %d\n", __COUNTER__); } while(0);

12voto

Potatoswatter Punkte 130562

Mich würde interessieren, ob es schon jemand benutzt hat,

Ja, aber wie Sie an vielen Beispielen in dieser Frage und Antwort sehen können, __LINE__ die genormt ist, würde in den meisten Fällen ebenfalls ausreichen.

__COUNTER__ ist nur in den Fällen wirklich notwendig, in denen die Zählung jedes Mal um eins erhöht werden muss, oder sie muss über mehrere #include Dateien.

und ob es sich lohnen würde, sie zu standardisieren?

__COUNTER__ im Gegensatz zu __LINE__ ist sehr gefährlich, weil es davon abhängt, welche Header-Dateien in welcher Reihenfolge eingebunden werden. Wenn zwei .cpp Dateien (Übersetzungseinheiten) enthalten eine Header-Datei, die __COUNTER__ aber die Header-Datei erhält unterschiedliche Zählsequenzen in den verschiedenen Instanzen, können sie unterschiedliche Definitionen der gleichen Sache verwenden und verletzen die Ein-Definitions-Regel.

Verstöße gegen Regeln mit einer Definition sind sehr schwer zu erkennen und können zu Fehlern und Sicherheitsrisiken führen. Die wenigen Anwendungsfälle von __COUNTER__ wiegen die Nachteile und die mangelnde Skalierbarkeit nicht wirklich auf.

Selbst wenn Sie niemals Code ausliefern, der __COUNTER__ Bei der Erstellung eines Prototyps für eine Aufzählungssequenz kann dies nützlich sein, da es Ihnen die Mühe erspart, Namen zuzuweisen, bevor die Mitgliedschaft konkret ist.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X