質問
呼ばれる自由関数があるとします InitFoo
. 。この機能を偶然に複数回呼び出すことから保護したいと思います。あまり考えずに、私は次のことを書きました:
void InitFoo()
{
{
static bool flag = false;
if(flag) return;
flag = true;
}
//Actual code goes here.
}
しかし、これは大きないぼのように見えます。 InitFoo
します いいえ 他の州の情報を保存する必要があります。誰かがugさなしに同じ目標を達成する方法を提案できますか?
もちろん、マクロは数えません。
解決
あなたはいくつかの異なるugさでそれをすることができます:
struct InitFoo
{
InitFoo()
{
// one-time code goes here
}
};
void Foo()
{
static InitFoo i;
}
あなたはまだ使用しています static
, 、しかし今、あなたはあなた自身のフラグチェックをする必要はありません - static
すでに旗と小切手を入れているので、構築するだけです i
一度。
他のヒント
さて、コンストラクターは自動的に1回だけ呼び出されます。このクラスの単一のインスタンスを作成する場合:
class Foo
{
public:
Foo(void)
{
// do stuff
}
}
それで //do stuff
1回だけ実行されます。 2回実行する唯一の方法は、クラスの別のインスタンスを作成することです。
これを使用してこれを防ぐことができます シングルトン. 。事実上、 //do stuff
おそらく一度だけ呼ばれる可能性があります。
この機能を偶然何度も呼び出すことから保護したい
私にとって、これはデバッグ中にしか出てくる問題のように聞こえます。その場合、私は単に次のことをします:
void InitFoo()
{
#ifndef NDEBUG
static bool onlyCalledOnce = TRUE;
assert(onlyCalledOnce);
onlyCalledOnce = FALSE;
#endif
...
}
この特定のいぼの目的は、それを見るだけで簡単に識別されます。プログラマーが電話をかけることを間違えると、すてきで大きくて派手な主張の失敗を引き起こします InitFoo
一回以上。また、生産コードで完全に消滅します。 (いつ NDEBUG
定義されています)。
編集: :モチベーションに関する簡単なメモ:
INIT機能を複数回呼び出すことは、おそらく大きなエラーです。この関数のエンドユーザーが誤ってそれを2回呼んだ場合、その間違いはおそらく進むべき道ではないでしょう。行かない場合 assert()
ルート、少なくともメッセージを投棄することをお勧めします stdout
また stderr
.
それがまさに私がそれをする方法です。代替案が必要な場合は、関数ポインターシャッフルを使用できます。
static void InitFoo_impl()
{
// Do stuff.
// Next time InitFoo is called, call abort() instead.
InitFoo = &abort;
}
void (*InitFoo)() = &InitFoo_impl;
また、マルチスレッドセーフである必要がありますか?ダブルチェックロックでシングルトンパターンを調べてください(これは驚くほど誤解しやすいです)。
このためにクラス全体を望まない場合、もう1つの簡単な方法は次のとおりです。
.cpp(.hでinitblahを宣言しないでください)
// don't call this -- called by blahInited initialization
static bool InitBlah()
{
// init stuff here
return true;
}
bool blahInited = InitBlah();
この.cppの外で誰もそれを呼ぶことはできず、呼び出されます。確かに、誰かがこの.cppでそれを呼ぶことができます - それが不可能であり、文書化されていることをどれだけ気にかけているかによって異なります。
あなたが特定の時間に注文またはそれをすることを気にかけているなら、シングルトンはおそらくあなたのためです。
私はまさにそのことを常にしています。もちろん、スレッド関連の問題について心配しないことを前提としています。通常、変数名を「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();
}