假设我有一个名为InitFoo
的免费函数。我想保护这个功能不被意外多次调用。我没有多想,写了以下内容:
void InitFoo()
{
{
static bool flag = false;
if(flag) return;
flag = true;
}
//Actual code goes here.
}
但这看起来像是一个大蠢。 InitFoo
不需要保留任何其他状态信息。有人可以提出一种方法来实现同一目标而不是丑陋吗?
当然,宏并不算数。
答案 0 :(得分:10)
你可以用一些不同的丑陋来做:
struct InitFoo
{
InitFoo()
{
// one-time code goes here
}
};
void Foo()
{
static InitFoo i;
}
您仍在使用static
,但现在您不需要自己执行标记检查 - static
已经放入标记并检查它,因此它只构造{{ 1}}一次。
答案 1 :(得分:3)
好吧,构造函数只会自动调用一次。如果您创建此类的单个实例:
class Foo
{
public:
Foo(void)
{
// do stuff
}
}
然后//do stuff
只执行一次。执行两次的唯一方法是创建该类的另一个实例。
您可以使用Singleton来防止这种情况发生。实际上,//do stuff
只能被调用一次。
答案 2 :(得分:1)
这正是我要做的。如果你想要一个替代方法,你可以使用一些函数指针改组:
static void InitFoo_impl()
{
// Do stuff.
// Next time InitFoo is called, call abort() instead.
InitFoo = &abort;
}
void (*InitFoo)() = &InitFoo_impl;
答案 3 :(得分:1)
我想保护此功能不被意外多次调用
对我而言,这听起来像是一个只会在调试过程中出现的问题。如果是这种情况,我会简单地执行以下操作:
void InitFoo()
{
#ifndef NDEBUG
static bool onlyCalledOnce = TRUE;
assert(onlyCalledOnce);
onlyCalledOnce = FALSE;
#endif
...
}
这个特定疣的目的只是通过观察它很容易辨别出来,如果程序员错误地多次调用InitFoo
,它将导致一个漂亮,大而华丽的断言失败。它也将完全消失在生产代码中。 (定义{{1}}时)。
编辑:关于动机的快速说明:
不止一次调用init函数可能是一个很大的错误。如果这个函数的最终用户错误地将它调用了两次,那么静静地忽略这个错误可能就不是了。如果您不采用NDEBUG
路线,我建议至少将信息转发至assert()
或stdout
。
答案 4 :(得分:0)
您是否还需要多线程安全?通过双重检查锁定来查看Singleton模式(这很容易出错)。
如果你不想要一个完整的课程,另一个简单的方法是:
在.cpp中(不要在.h中声明InitBlah)
// don't call this -- called by blahInited initialization
static bool InitBlah()
{
// init stuff here
return true;
}
bool blahInited = InitBlah();
没有人可以在.cpp之外调用它,它会被调用。当然,有人可以在这个.cpp中调用它 - 取决于你关心多少,这是不可能的,不方便和记录。
如果您关心订单或在特定时间进行订购,那么Singleton可能适合您。
答案 5 :(得分:0)
我一直都是这样做的,需要一次性但不值得制作全班的情况。当然,它假设您不担心与线程相关的问题。我通常在变量名前加上“s_”,以明确它是一个静态变量。
答案 6 :(得分:0)
嗯...如果您不反对使用Boost,请查看boost::call_once:
namespace { boost::once_flag foo_init_flag = BOOST_ONCE_INIT; }
void InitFoo() {
// do stuff here
}
void FooCaller() {
boost::call_once(&foo_init_flag, InitFoo);
// InitFoo has been called exactly once!
}
void AnotherFooCaller() {
boost::call_once(&foo_init_flag, InitFoo);
// InitFoo has been called exactly once!
}
答案 7 :(得分:0)
并非我对此感到非常兴奋,但这只是另一种方式:功能对象。
#import <iostream>
class CallOnce {
private:
bool called;
public:
CallOnce() {
called = false;
}
void operator()(void) {
if (called) {
std::cout << "too many times, pal" <<std::endl;
return;
}
std::cout << "I was called!" << std::endl;
called = true;
}
};
int main(void) {
CallOnce call;
call();
call();
}