Einmaliger Block an beliebiger Stelle im Code (C ++ 11 und höher)

Ich möchte eine kleine vorgefertigte Lösung für diejenigen vorstellen, die möglicherweise einen großen (oder nicht so großen) Teil des Codes schreiben müssen, den das Programm genau einmal ausführen soll. und Sie müssen es möglicherweise irgendwo platzieren (innerhalb der angemessenen Grenzen und C ++ - Syntaxregeln). Wenn dies im gesamten Projekt öfter als ein paar Mal erforderlich ist, wäre es schön, wenn zumindest ein Teil mehr oder weniger funktioniert und wenn möglich keine sehr gute Krückenlösung.

Auf den Punkt gebracht


Ohne lange nachzudenken, poste ich sofort meinen Code, der mit dem Standard C ++ 11 und höher funktioniert.

#include 
#define DO_ONCE(...)  { static bool _do_once_ = ([&](){ __VA_ARGS__ }(), true); (void)_do_once_; }
void Foo(int val)
{
    using namespace std;
    // Имя _do_once_ никак не конфликтует с переменной в макросе DO_ONCE
    static unsigned int _do_once_ = 1;
    DO_ONCE
    (
       cout << "[First call of 'Foo' function]" << endl;
    )
    cout << "Calls: " << _do_once_++ << ", value: " << val << endl;
}
int main(int argc, char** argv)
{
    using namespace std;
    for (auto val : {1, 2, 3})
    {
        Foo(val);
        DO_ONCE
        (
            Foo(val);
        )
    }
    system("pause > nul");
    return 0;
}
/* Результат работы:
[First call of 'Foo' function]
Calls: 1, value: 1
Calls: 2, value: 1
Calls: 3, value: 2
Calls: 4, value: 3
/*

Betrachten Sie den wichtigsten Code, der die gesamte erforderliche Arbeit leistet:

#define DO_ONCE(...)  { static bool _do_once_ = ([&](){__VA_ARGS__}(), true); (void)_do_once_; }

Es sieht nicht sehr klar und schön aus, daher schreibe ich etwas mehr:

#define DO_ONCE(...)  \
{  \
    static bool _do_once_ = ([&] ( ) { __VA_ARGS__ } ( ), true);  \
    (void)_do_once_;  \
}

So funktioniert es - im Codeblock wird eine lokale statische Variable vom Typ bool erzeugt, die mit dem Operator "Komma" in zwei Schritten initialisiert wird:

1. Mit dem Operator "Klammern" wird das Lambda aufgerufen:

[&] ( )
{
    __VA_ARGS__
}

Das erfasst anhand von Verweisen alles, was sich im Gültigkeitsbereich befindet, und führt den Ausdruck aus, den der Benutzer durch in __VA_ARGS__ „gepackte“ Argumente an das DO_ONCE-Makro übergeben hat . Mit dem vordefinierten Makro __VA_ARGS__ können Sie den gesamten Code im Block speichern, auch wenn er Kommas enthält (die der Präprozessor beim Analysieren als Begrenzer für Argumente betrachtet).

2. Die Variable _do_once_ wird auf true gesetzt (der zugewiesene Wert und der Typ der Variablen selbst spielen keine Rolle, ohne die im Programm belegte Größe zu zählen). Der Eintrag "(void) _do_once_;" erforderlich, um eine Warnung vor einer nicht verwendeten Variablen zu vermeiden.

Zu diesem Zeitpunkt ist die Initialisierung der Variablen abgeschlossen und es wird niemals mehr als dieser Code ausgeführt, was erforderlich war, um dies zu erreichen.

Nachteile des Ansatzes:

- Erfordert den C ++ 11-Standard
- Erfordert 1 Variable pro DO_ONCE-Block.

Vorteile:

- Gute Lesbarkeit, einfache Syntax.
- Es gibt keine Einschränkungen hinsichtlich der Anzahl der Anweisungen im Block und ihres Typs (versuchen Sie nicht, break einzugeben und dort fortzufahren, wenn sich der Zyklus außerhalb des DO_ONCE-Blockkörpers befindet oder die case-Beschriftung, wenn sich DO_ONCE innerhalb des Schalters befindet).
- Möglichkeit, mit Variablen und Funktionen zu arbeiten, die im Rahmen des DO_ONCE-Aufrufs verfügbar sind, ohne dass zusätzliche Kosten für die Übergabe dieser Variablen als Argumente anfallen.
- Es besteht kein Risiko, dass der Fehler auftritt, die Variable _do_once_ zu überschreiben, weil Im Hauptteil des Blocks ersetzt es einfach diesen Namen aus dem äußeren Bereich.

Verwendete Literatur:
" Lambda-Ausdrücke
"Makro mit variablen Argumentlisten

Jetzt auch beliebt: