我有一个应用程序,其中包含多个功能。可以根据用户输入多次调用每个函数。但是,我需要在函数中执行一小段代码,最初只在应用程序启动时执行。当在稍后的时间点再次调用此相同的函数时,不得执行此特定代码段。代码在 VC ++ 中。请告诉我处理此问题的最有效方法。
答案 0 :(得分:24)
使用带有构造函数的全局静态对象(在main
之前调用)?或者只是在例程中
static bool initialized;
if (!initialized) {
initialized = true;
// do the initialization part
}
很少有这种情况不够快!
在多线程环境中,这可能还不够:
您可能还对pthread_once或constructor
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的if
和std::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)