如何只执行一段代码一次

How to execute a piece of code only once?

本文关键字:代码 一次 一段 执行      更新时间:2023-10-16

我有一个应用程序,其中有几个功能。每个函数都可以根据用户输入被调用多次。然而,我需要在函数中执行一小段代码,只有一次,最初是在启动应用程序时。当在稍后的时间点再次调用同一函数时,必须不执行这段特定的代码。代码在 vc++ 中。请告诉我处理这件事最有效的方法。

使用lambda函数的精简版:

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

lambda函数中的代码只执行一次,当静态变量初始化为lambda函数的返回值时。只要编译器支持线程安全的静态初始化,它就应该是线程安全的。

使用c++ 11——使用std::call_once

#include <mutex>
std::once_flag onceFlag;
{
    ....
    std::call_once ( onceFlag, [ ]{ /* my code body here runs only once */ } );
    ....
}

使用全局静态对象与构造函数(在main之前调用)?或者只是在一个例程中

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

在很少的情况下,这还不够快!


附录

在多线程上下文中,这可能不够:

您可能还对GCC的pthread_once或 constructor 函数__attribute__感兴趣。

在c++ 11中,您可能需要std::call_once.

如果你的函数可以从多个线程调用,你可能想使用<atomic>,也许声明static volatile std::atomic_bool initialized;(但你需要小心)。

但是这些可能在您的系统上不可用;它们在Linux上是可用的!

可以使用本地静态变量:

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

除了@Basile的答案之外,您还可以使用lambda封装静态变量,如下所示:

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

你可以这样做吗

有一个返回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;
}
对C

#include <stdio.h>
void init()
{
    printf("initn");
}
void process()
{
    static int someint = 0;
    if(someint == 0)
    {
        someint = 1;
        init();
    }
    printf("processn");
}

int main()
{
    process();
    process();
    process();
    return 0;
}

std::call_once() 等。如果您不需要完全线程安全的解决方案,可能是多余的。

如果没有,我们可以使用c++ 17的初始化-within- ifstd::exchange():

来使它看起来特别优雅。
#include <utility>
void
do_something_expensive_once()
{
    if ( static auto called = false; !std::exchange(called, true) ) {
        do_something_expensive();
    }
}

如果这是一个你经常使用的模式,那么我们可以通过一个标签类型来封装它:

#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 expensiven";
}
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;
}

这将只打印something expensive一次。结果!它还使用了在模板参数列表中声明标记struct的功能,以最大限度地简化。

或者,你可以模板一个函数的地址,一个唯一的整数,等等。

您还可以将一个可调用对象传递给call_once(),等等。一如既往的c++:可能性是无限的!

考虑到std::call_once()和通常关于线程安全的警告,这里有另一个轻量级选项,它可以避免未使用的变量警告,并使我们的标志保持在块范围内:

for (static bool once=true; once; once=false) {
    yourCodeHere();
}
do { 
     //execute code once
} while (false)