Как выполнить кусок кода только один раз? - PullRequest
16 голосов
/ 07 декабря 2011

У меня есть приложение, в котором есть несколько функций.Каждая функция может вызываться много раз в зависимости от пользовательского ввода.Однако мне нужно выполнить небольшой сегмент кода внутри функции только один раз, изначально при запуске приложения.Когда эта же функция вызывается снова в более поздний момент времени, этот конкретный фрагмент кода не должен выполняться.Код находится в VC ++ .Скажите, пожалуйста, наиболее эффективный способ справиться с этим.

Ответы [ 6 ]

24 голосов
/ 07 декабря 2011

Использовать глобальные статические объекты с конструкторами (которые вызываются до main)? Или просто внутри рутины

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

Очень мало случаев, когда это не достаточно быстро!


добавления

В многопоточном контексте этого может быть недостаточно:

Вы также можете быть заинтересованы в pthread_once или constructor функция __attribute__ GCC .

С C ++ 11 вы можете захотеть std :: call_once .

Возможно, вы захотите использовать <atomic> и, возможно, объявить static volatile std::atomic_bool initialized; (но вы должны быть осторожны), если ваша функция может быть вызвана из нескольких потоков.

Но они могут быть недоступны в вашей системе; они доступны в Linux!

21 голосов
/ 13 апреля 2016

Компактная версия с использованием лямбда-функции:

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

Код в лямбда-функции выполняется только один раз, когда статическая переменная инициализируется возвращаемым значением лямбда-функции. Он должен быть поточно-ориентированным, если ваш компилятор поддерживает поточно-ориентированную статическую инициализацию.

19 голосов
/ 21 июня 2014

Использование C ++ 11 - используйте std::call_once

#include <mutex>

std::once_flag onceFlag;

{
    ....
    std::call_once ( onceFlag, [ ]{ /* my code body here runs only once */ } );
    ....
}
15 голосов
/ 07 декабря 2011

Вы можете использовать локальную статическую переменную:

void foo()
{
     static bool wasExecuted = false;
     if (wasExecuted)
         return;
     wasExecuted = true;

     ...
}
5 голосов
/ 17 октября 2013

могли бы вы сделать это

иметь функцию, которая возвращает тип bool или некоторый тип данных, называемый init

Я сделал это таким образом, вам нужен статический bool, чтобы это произошло

bool init()
{
  cout << "Once " <<endl;
  return true||false;// value isn't matter
}

void functionCall()
{
    static bool somebool = init(); // this line get executed once
    cout << "process " <<endl;
}

int main(int argc, char *argv[])
{
    functionCall();
    functionCall();
    functionCall();

    return EXIT_SUCCESS;
}
4 голосов
/ 15 июня 2014

В дополнение к ответу @ Basile вы можете использовать лямбду для инкапсуляции статической переменной следующим образом:

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
}

Это упрощает преобразование в макрос общего назначения:

#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; } ())

Который можно разместить где угодно по требованию :

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

И для хорошей меры, атомика сокращает выражение и делает его поточно-ориентированным:

#include <atomic>
#define FIRST_TIME_HERE ([] { \
    static std::atomic<bool> first_time(true); \
    return first_time.exchange(false); } ())
...