如何只执行一段代码?

时间:2011-12-07 08:59:49

标签: c++ static global-variables

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

8 个答案:

答案 0 :(得分:24)

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

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

很少有这种情况不够快!


附加物

在多线程环境中,这可能还不够:

您可能还对pthread_onceconstructor function __attribute__ of GCC感兴趣。

使用C ++ 11,您可能需要std::call_once

如果可以从多个线程调用函数,则可能需要使用<atomic>并声明static volatile std::atomic_bool initialized;(但需要注意)。

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

答案 1 :(得分:21)

使用lambda函数的紧凑版本:

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

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

答案 2 :(得分:19)

使用C ++ 11 - 使用std::call_once

#include <mutex>

std::once_flag onceFlag;

{
    ....
    std::call_once ( onceFlag, [ ]{ /* my code body here runs only once */ } );
    ....
}

答案 3 :(得分:15)

您可以使用本地静态变量:

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

     ...
}

答案 4 :(得分:5)

你可以这样做吗

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

答案 5 :(得分:3)

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

可将其放置在您想要的任何位置call-by-need

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

为了更好地衡量,atomics缩短了表达式并使其成为线程安全的:

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

答案 6 :(得分:1)

从C ++ 11开始,静态局部变量是线程安全的,并且通常在大多数情况下就足够了,因此std::call_once() 可能会过大。

在使用C ++ 17的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 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;
}

这只会打印something expensive一次。结果!它还具有在模板参数列表中声明标签struct的功能,以最大程度地简化。

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

然后,您还可以将可调用对象传递给call_once(),依此类推,依此类推。和C ++一样,可能性是无限的!

答案 7 :(得分:-1)

do { 
     //execute code once
} while (false)