假设我有一个免费的功能 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();
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top