我有一个应用程序,其中包含几个功能。每个功能都可以根据用户输入被多次调用。但是我需要在应用程序启动时仅执行函数中的一小段代码一次。当此后在稍后时间再次调用同一函数时,这个特定的代码段不应该被执行。 代码使用VC++编写,请告诉我处理此问题的最有效方法。
我有一个应用程序,其中包含几个功能。每个功能都可以根据用户输入被多次调用。但是我需要在应用程序启动时仅执行函数中的一小段代码一次。当此后在稍后时间再次调用同一函数时,这个特定的代码段不应该被执行。 代码使用VC++编写,请告诉我处理此问题的最有效方法。
使用lambda函数的紧凑版:
void foo()
{
static bool once = [](){
cout << "once" << endl;
return true;
} ();
cout << "foo" << endl;
}
lambda函数内的代码仅在静态变量初始化为lambda函数返回值时执行一次。只要编译器支持线程安全的静态初始化,它就应该是线程安全的。
run_once()
)。 - Alexis Wilke使用 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
}
很少情况下会发生这个不够快的情况!
在多线程环境中,这可能还不足够:
您可能还需要pthread_once或__attribute__
函数构造器
的GCC。
有了C++11,您可能会想要使用std::call_once。
如果您的函数可以从多个线程调用,则可能需要使用<atomic>
并声明static volatile std::atomic_bool initialized;
(但需小心)。
但是这些可能在您的系统上无法使用;它们在Linux上可用!
static bool initialized(false);
否则,一旦分配内存,您就不知道其中会有什么。 - thaynestatic
变量被初始化为全零位,对于bool
类型来说是false
。 - Basile Starynkevitch您可以使用局部静态变量:
void foo()
{
static bool wasExecuted = false;
if (wasExecuted)
return;
wasExecuted = true;
...
}
你能做这个吗?
需要一个返回布尔值或名为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;
}
对于C语言
#include <stdio.h>
void init()
{
printf("init\n");
}
void process()
{
static int someint = 0;
if(someint == 0)
{
someint = 1;
init();
}
printf("process\n");
}
int main()
{
process();
process();
process();
return 0;
}
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); } ())
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 ++一样:可能性是无限的!static auto called
以线程安全的方式初始化为false
。但是,对std::exchange
的并发调用不能保证被序列化。因此,你可能会多次调用do_something_expensive
。 - igor.solif ( static auto called = false; !called ) { do_something_expensive();called = true; }
- igor.sol尊重 std::call_once()
,并注意线程安全的常规警告,这里提供另一个轻量级选项,避免未使用变量的警告,并将我们的标志保持在块范围内:
for (static bool once=true; once; once=false) {
yourCodeHere();
}
do {
//execute code once
} while (false)
do
/while
没有任何作用,也绝对不能确保其中的代码仅在包含函数的第一次调用时执行一次。 - underscore_ddo
/while
没有任何作用,特别是不能使调用后的代码不运行。你回答了“如何使N行代码只运行一次”的问题,这并不是一个真正的问题,因为答案只是“写一次”...一个虚假的循环完全没有增加任何东西。 - underscore_d
main
函数中?或者放在程序的 主循环 之前? - Kiril Kirov