さて、私は自分の経験を共有することによってこれに答えます。通常、クラスにすべての独自の機能を持たせたいのですが、後でわかりました。これには、特異なオブジェクトのインスタンスを他のコードに提供するためのファクトリメソッドが必要になる場合があります。インスタンスは、状態などを維持するために実際には1回だけ定義する必要があります。したがって、これは、初期化のすべてが構築にラップされていないクラスに対して行うことです。既存のクラスをsingletonsuxnessで乱雑にしたくないので、これを支援するためにファクトリラッパークラスを作成します。静的ローカル変数の実装(静的ローカル初期化のコンパイラ実装に依存しますが、これは必ずしも良い考えではありません)にロックを処理させることで、エレガントでロックをカプセル化するMyerのシングルトンパターンを使用できますが、次のような場合に問題が発生します。自分、
class X
{
public:
bool isInitialized () { return _isInitialized; } ; // or some method like
// establishCxn to have it
// bootstrapped
void initialize();
X() {} // constructor default, not initialized, light weight object
private:
bool _isInitialzied;
};
// set initialization to false
X::X(): _isInitialized(false) {}
void X::intialize()
{
if (isInitiazlied()) { return; }
.... init code ....
_isInitialized = true
}
// now we go ahead and put a factory wrapper on top of this to help manage the
// singletoness nature. This could be templatized but we don't as we want the
// flexibility to override our own getinstance to call a specific initialize for the
// object it is holding
class XFactory
{
public:
static X* getInstance();
private:
static boost::mutex _lock;
// light weight static object of yourself ( early instantiation ) to put on the stack
// to avoid thread issues, static method member thread saftey, and DCLP pattern
// threading races that can stem from compiling re-ordering of items
static XFactory _instance;
// making this pointer volatile so that the compiler knows not to reorder our
// instructions for it ( depends on compiler implementation but it is a safe guard )
X* volatile _Xitem;
X* getXitem () { return _Xitem; }
void createInstance();
void doCleanUp();
// stop instantiation or unwanted copies
XClientFactory();
~XClientFactory();
XClientFactory(XClientFactory const&);
XClientFactory& operator=(XClientFactory const&);
};
// on construction we create and set the pointer to a new light weight version of the
// object we are interested in construction
XFactory::XFactory() : _Xitem( new X; )
{
}
// note our factory method is returning a pointer to X not itself (XFactory)
X* XFactory::getInstance()
{
// DCLP pattern, first thread might have initialized X while others
// were waiting for the lock in this way your double check locking is
// on initializing the X container in the factory and not the factory object itself.
// Worst case your initialization could happen more than once but it should check the
// boolean before it starts (see initialization method above) and sets the boolean at
// the end of it. Also your init should be such that a re-initialization will not put
// the object in a bad state. The most important thing to note is that we
// moved the double check locking to the contained object's initialization method
// instead of the factory object
if (! XFactory::_instance.getXitem()->isInitialized() )
{
boost::unique_lock<boost::mutex> guard(XFactory::_lock);
if (! XFactory::_instance.getXitem()->isInitialized() )
{
XFactory::_instance.getXitem()->initialize();
}
}
return XFactory::_instance.getXitem();
}
// XFactory private static instance on the stack will get cleaned up and we need to
// call the delete on the pointer we created for the _Xitem
XFactory::~XFactory()
{
doCleanUp();
}
XFactory::doCleanUp()
{
delete _Xitem; //
}
それだけです、あなたの考えを教えてください。私も最近シングルトンと格闘し、すべてのピットが落ちました。また、0xコンパイラはまだ使用していません。これにより、ローカル静的変数を使用するだけで、Myersシングルトンがスレッドセーフな方法で実装されることが保証されます。