题
假设我有一个免费的功能 InitFoo
. 。我想保护此功能免受偶然被称为多次。没有太多想到我写了以下内容:
void InitFoo()
{
{
static bool flag = false;
if(flag) return;
flag = true;
}
//Actual code goes here.
}
不过,这看起来像是一头大疣。 InitFoo
做 不是 需要保留任何其他州信息。有人可以建议在没有丑陋的情况下实现相同目标的方法吗?
当然,宏不算数。
解决方案
您可以以不同的丑陋来做到这一点:
struct InitFoo
{
InitFoo()
{
// one-time code goes here
}
};
void Foo()
{
static InitFoo i;
}
您仍在使用 static
, ,但是现在您无需进行自己的标志检查 - static
已经放在标志和支票上,因此仅构建 i
一次。
其他提示
好吧,构造函数仅自动称为一次。如果您创建此类的单个实例:
class Foo
{
public:
Foo(void)
{
// do stuff
}
}
然后 //do stuff
只能执行一次。执行两次的唯一方法是创建类的另一个实例。
您可以通过使用 辛格尔顿. 。有效, //do stuff
只能被称为一次。
我想保护此功能免受偶然被称为多次
对我来说,这听起来像是一个只有在调试期间出现的问题。如果是这种情况,我只会做以下操作:
void InitFoo()
{
#ifndef NDEBUG
static bool onlyCalledOnce = TRUE;
assert(onlyCalledOnce);
onlyCalledOnce = FALSE;
#endif
...
}
仅通过查看,这种特殊疣的目的就很容易辨别出来,如果程序员犯了呼叫的错误,它将导致一个不错的,大,浮华的断言失败 InitFoo
不止一次。它也将完全消失生产代码。 (什么时候 NDEBUG
被定义为)。
编辑: :关于动机的快速说明:
调用初始化功能不止一次可能是一个大错误。如果此功能的最终用户错误地将其称为两次,那么悄悄地忽略了这个错误可能不是要走的路。如果你不去 assert()
路线,我建议至少将消息倾倒到 stdout
或者 stderr
.
这就是我的做法。如果您需要替代方案,则可以使用一些功能指针改组:
static void InitFoo_impl()
{
// Do stuff.
// Next time InitFoo is called, call abort() instead.
InitFoo = &abort;
}
void (*InitFoo)() = &InitFoo_impl;
您还需要它是多线程安全的吗?查看具有双检查锁定的单例图案(这很容易出错)。
如果您不想整个课程,另一种简单的方法是:
在.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可能适合您。
我一直都在做需要一次性的,但不是一个阶级的情况。当然,它假设您不必担心与线程有关的问题。我通常将变量名称带有“ S_”,以表明它是静态变量。
嗯...如果您不反对使用 促进, ,然后看看 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!
}
并不是说我对此感到非常兴奋,但这只是另一种方法:功能对象。
#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();
}