C++ 如何只执行一段代码一次?

C++ 如何只执行一段代码一次?,c++,static,global-variables,C++,Static,Global Variables,我有一个应用程序,其中有几个功能。每个函数都可以根据用户输入多次调用。然而,我只需要在一个函数中执行一小段代码一次,最初是在应用程序启动时。当稍后再次调用此函数时,不得执行此特定代码段。代码是用VC++编写的。请告诉我最有效的处理方法。将全局静态对象与构造函数一起使用(在main之前调用)?或者只是在例行程序中 static bool initialized; if (!initialized) { initialized = true; // do the initializati

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

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

static bool initialized;
if (!initialized) {
   initialized = true;
   // do the initialization part
}
很少有情况下这不够快


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

您也可能对或感兴趣

使用C++11,您可能需要

您可能希望使用并可能声明
静态volatile std::atomic\u bool initialized(但需要小心)如果可以从多个线程调用函数


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

您可以使用局部静态变量:

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

     ...
}
你能这样做吗

有一个函数返回一个bool或一些名为init的数据类型

我是这样做的,你需要静态布尔来实现它

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

cout除了@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; } ())
可放置在您想要的任何位置:

为了更好地测量,请缩短表达式并使其线程安全:

#include <atomic>
#define FIRST_TIME_HERE ([] { \
    static std::atomic<bool> first_time(true); \
    return first_time.exchange(false); } ())
#包括
#在此处定义第一次([]{\
静态标准::原子第一时间(真)\
返回第一次交换(false);}())
使用C++11——使用
std::call\u一次

#include <mutex>

std::once_flag onceFlag;

{
    ....
    std::call_once ( onceFlag, [ ]{ /* my code body here runs only once */ } );
    ....
}
#包括
std::once_标志onceFlag;
{
....
std::call_once(onceFlag,[]{/*我的代码体在这里只运行一次*/});
....
}

使用lambda功能的紧凑型版本:

void foo()
{
    static bool once = [](){
        cout << "once" << endl;
        return true;
    } ();
    cout << "foo" << endl;
}
void foo()
{
静态bool once=[](){
cout
std::call_once()
等。如果您不需要完全线程安全的解决方案,那么这可能是一种过分的做法

如果没有,我们可以在-
If
中使用C++17的初始化,使其看起来特别优雅,并且:

#包括
无效的
做一次昂贵的事
{
if(static auto called=false;!std::exchange(called,true)){
做一些昂贵的事;
}
}
如果这是您经常使用的模式,那么我们可以通过标记类型来封装它:

#包括
#包括
模板
汽车
打电话给你一次
{
静态自动调用=错误;
return!std::exchange(调用,true);
}
无效的
做些昂贵的事
{
std::cout int
{
用于(自动i=0;i<5;++i){
做一次昂贵的事;
}
返回0;
}
这将只打印一次昂贵的
内容。结果!它还使用在模板参数列表中声明标记
struct
的功能,以实现最大的简洁性

或者,您可以在函数的地址、唯一整数等上设置模板


然后,您还可以传递一个callable to
call_once()
,依此类推。对于C++来说,像往常一样:可能性是无穷的!

您不能把它放在开头(或任何需要的地方)吗在
main
?或在程序的主循环之前?这也是我的想法,但在读到@KirilKirov的评论后,我不得不用头撞上一些石头。干杯,这不会像在多线程设置中那样工作,但对大多数用例应该是好的。确保将bool初始化为false!
静态bool initialized(false)
否则一旦分配,你永远不知道内存中会有什么。好吧,一个
静态
变量被初始化为所有零位,这对于
bool
来说是
从C++11开始这是线程安全的。是的,静态变量被初始化为零。但是,我仍然认为保持总是显式ini的习惯是很好的tialising primitive Type;这样,如果它被重构为不隐式初始化,你以后就不会陷入恐惧。我不知道这个API,谢谢。有两件事:首先确保onceFlag具有全局作用域。它不能具有线程或函数作用域。其次,我看不到一种方法可以轻松地将其压缩为单个表达式。(与拥有清晰、标准的API相比,这不是什么大不了的事情。)我用它来影响很大,我唯一要改进的是,如果你将函数中的once_标记声明为static,它将只初始化一次,而你的代码内部call_once将只运行一次,但是你可以将所有代码保持在同一个范围内。它执行一次是因为“static将只初始化一次”吗??很好,我认为编译器在初始化静态文件时已经这样做了,因此我们应该能够从中受益,下面是正确的答案(而不是使用标志或
run_once()
)@Bediver如果您将lambda存储在自动变量中而不是立即执行它,它将能够被多次调用。或者是UB?这将显示一条警告“警告:未使用的变量”一次[-Wunused variable]”。使用C++17,您可以使用[[maybe_unused]]如果您将此生成的汇编代码与使用std::call_时生成的汇编代码进行比较,则此代码看起来好多了!欢迎downvoter来启发我,因为我修复了一个简单的打字错误,这是我在这里唯一能看到的错误。我不是downvoter,但您的代码不正确。是
静态自动调用
是以线程安全的方式初始化为
false
。但是,对
std::exchange
的并发调用不能保证序列化。因此,您可以多次调用
do_something
。OP没有指定需要线程安全的解决方案,如果不需要,也可以。这并不意味着“我的代码不正确”,而是继续卑鄙
do { 
     //execute code once
} while (false)
void foo()
{
    static bool once = [](){
        cout << "once" << endl;
        return true;
    } ();
    cout << "foo" << endl;
}
do { 
     //execute code once
} while (false)