2

と呼ばれる自由な関数があるとしInitFooます。この関数が誤って複数回呼び出されないように保護したいと思います。あまり考えずに次のように書きました。

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

    //Actual code goes here.
}

しかし、これは大きないぼのように見えます。他の状態情報を保持する必要はありInitFooません。誰かが醜いことなく同じ目標を達成する方法を提案できますか?

もちろん、マクロはカウントされません。

4

8 に答える 8

10

あなたはいくつかの異なる醜さでそれを行うことができます:

struct InitFoo
{
     InitFoo()
     {
         // one-time code goes here
     }
};

void Foo()
{
    static InitFoo i;
}

まだ を使用staticしていますが、独自のフラグ チェックを行う必要はありません。static既にフラグとそのチェックを入れているため、一度だけ構築さiれます。

于 2009-07-20T22:11:54.720 に答える
3

コンストラクターは自動的に 1 回だけ呼び出されます。このクラスの単一のインスタンスを作成する場合:

class Foo
{
public:
    Foo(void)
    {
        // do stuff
    }
}

その後//do stuff、一度だけ実行されます。これを 2 回実行する唯一の方法は、クラスの別のインスタンスを作成することです。

Singletonを使用することでこれを防ぐことができます。実際には、//do stuff一度しか呼び出せない可能性があります。

于 2009-07-20T22:09:49.327 に答える
1

それはまさに私がそれをする方法です。別の方法が必要な場合は、関数ポインターのシャッフルを使用できます。

static void InitFoo_impl()
{
    // Do stuff.

    // Next time InitFoo is called, call abort() instead.
    InitFoo = &abort;
}

void (*InitFoo)() = &InitFoo_impl;
于 2009-07-20T22:14:42.423 に答える
1

この関数が誤って複数回呼び出されるのを防ぎたい

私には、これはデバッグ中にのみ発生する問題のように思えます。その場合、私は単に次のことを行います。

void InitFoo()
{
    #ifndef NDEBUG
       static bool onlyCalledOnce = TRUE;
       assert(onlyCalledOnce);
       onlyCalledOnce = FALSE;
    #endif

    ...
}

この特定の疣贅の目的は、それを見るだけで簡単に識別できます。プログラマーがInitFoo2 回以上呼び出すというミスを犯した場合は、大きく派手なアサーション エラーが発生します。また、製品コードでは完全に消えます。(NDEBUGが定義されている場合)。

edit : 動機に関する簡単なメモ:
init 関数を複数回呼び出すことは、おそらく大きなエラーです。この関数のエンド ユーザーが誤って 2 回呼び出した場合、その間違いを静かに無視することはおそらく適切ではありません。ルートに行かない場合はassert()、少なくともメッセージをstdoutまたはにダンプすることをお勧めしますstderr

于 2009-07-20T22:18:53.740 に答える
0

私は、クラス全体を作成する価値がない、一度だけ必要な状況で常にそれを行っています。もちろん、スレッド関連の問題について心配していないことを前提としています。通常、変数名の前に「s_」を付けて、静的変数であることを明確にします。

于 2009-07-20T22:35:03.020 に答える
0

マルチスレッドセーフにする必要もありますか? ダブルチェック ロックを使用したシングルトン パターンを調べます (これは驚くほど間違いやすいものです)。

このためにクラス全体が必要ない場合は、別の簡単な方法は次のとおりです。

.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 が最適です。

于 2009-07-20T22:18:34.787 に答える
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!
}
于 2009-07-21T03:26:03.173 に答える
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();
}
于 2009-07-21T03:35:05.573 に答える