How to execute a piece of code only once?

后端 未结 8 803
隐瞒了意图╮
隐瞒了意图╮ 2020-12-01 04:35

I have an application which has several functions in it. Each function can be called many times based on user input. However I need to execute a small segment of the code wi

相关标签:
8条回答
  • 2020-12-01 05:06

    Additionally to @Basile's answer, you can use a lambda to encapsulate the static variable as follows:

    if ([] {
        static bool is_first_time = true;
        auto was_first_time = is_first_time;
        is_first_time = false;
        return was_first_time; } ()) 
    { 
        // do the initialization part
    }
    

    This makes it easy to convert into a general-purpose macro:

    #define FIRST_TIME_HERE ([] { \
        static bool is_first_time = true; \
        auto was_first_time = is_first_time; \
        is_first_time = false; \
        return was_first_time; } ())
    

    Which can be placed anywhere you want call-by-need:

    if (FIRST_TIME_HERE) {
        // do the initialization part
    }
    

    And for good measure, atomics shorten the expression and make it thread-safe:

    #include <atomic>
    #define FIRST_TIME_HERE ([] { \
        static std::atomic<bool> first_time(true); \
        return first_time.exchange(false); } ())
    
    0 讨论(0)
  • 2020-12-01 05:06

    As of C++11, static local variables are thread-safe and usually sufficient for most cases, so std::call_once() et al. very well may be overkill.

    This looks especially elegant when using C++17's initialisation-within-if and std::exchange():

    #include <utility>
    
    void
    do_something_expensive_once()
    {
        if ( static auto called = false; !std::exchange(called, true) ) {
            do_something_expensive();
        }
    }
    

    If this is a pattern you use a lot, then we can encapsulate it via a tag type:

    #include <iostream>
    #include <utility>
    
    template <typename T>
    auto
    call_once()
    {
        static auto called = false;
        return !std::exchange(called, true);
    }
    
    void
    do_something_expensive()
    {
        std::cout << "something expensive\n";
    }
    
    void
    do_something_expensive_once()
    {
        if ( call_once<struct TagForSomethingExpensive>() ) {
            do_something_expensive();
        }
    }
    
    auto
    main() -> int
    {
        for (auto i = 0; i < 5; ++i) {
            do_something_expensive_once();
        }
    
        return 0;
    }
    

    This will only print something expensive a single time. Result! It also uses the ability to declare a tag struct in a template argument list, for maximal brevity.

    Alternatively, you could template on a function's address, a unique integer, etc.

    You can then also pass a callable to call_once(), and so on, and so forth. As usual for C++: the possibilities are endless!

    0 讨论(0)
  • 2020-12-01 05:09

    Use global static objects with constructors (which are called before main)? Or just inside a routine

    static bool initialized;
    if (!initialized) {
       initialized = true;
       // do the initialization part
    }
    

    There are very few cases when this is not fast enough!


    addenda

    In multithreaded context this might not be enough:

    You may also be interested in pthread_once or constructor function __attribute__ of GCC.

    With C++11, you may want std::call_once.

    You may want to use <atomic> and perhaps declare static volatile std::atomic_bool initialized; (but you need to be careful) if your function can be called from several threads.

    But these might not be available on your system; they are available on Linux!

    0 讨论(0)
  • 2020-12-01 05:13

    Compact version using lambda function:

    void foo()
    {
        static bool once = [](){
            cout << "once" << endl;
            return true;
        } ();
        cout << "foo" << endl;
    }
    

    Code within lambda function is executed only once, when the static variable is initialized to the return value of lambda function. It should be thread-safe as long as your compiler support thread-safe static initialization.

    0 讨论(0)
  • 2020-12-01 05:17

    Using C++11 -- use the std::call_once

    #include <mutex>
    
    std::once_flag onceFlag;
    
    {
        ....
        std::call_once ( onceFlag, [ ]{ /* my code body here runs only once */ } );
        ....
    }
    
    0 讨论(0)
  • 2020-12-01 05:18

    You can use local static variable:

    void foo()
    {
         static bool wasExecuted = false;
         if (wasExecuted)
             return;
         wasExecuted = true;
    
         ...
    }
    
    0 讨论(0)
提交回复
热议问题