功能呼叫保护

时间:2009-07-20 22:07:00

标签: c++ function call guard

假设我有一个名为InitFoo的免费函数。我想保护这个功能不被意外多次调用。我没有多想,写了以下内容:

void InitFoo()
{
    {
        static bool flag = false;
        if(flag) return;
        flag = true;
    }

    //Actual code goes here.
}

但这看起来像是一个大蠢。 InitFoo 需要保留任何其他状态信息。有人可以提出一种方法来实现同一目标而不是丑陋吗?

当然,宏并不算数。

8 个答案:

答案 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();
}