まず、他の人が言ったように、これに対する明白な (そして最良の) 答えはシングルトンです。ただし、マルチスレッド要件を追加したため、オブジェクトがシングルトンを使用するコードによって変更されるかどうかに応じて、2 つの解決策があります。(あなたの説明から、私はそうではありません。)そうでない場合は、シングルトンの「ナイーブ」実装を使用し、スレッドが開始される前にシングルトンが初期化されるようにするだけで十分です。main に入る前にスレッドが開始されていない場合 (それ以外の場合は悪い習慣だと思います)、次のようなもので十分です。
class Singleton
{
static Singleton const* ourInstance;
Singleton();
Singleton( Singleton const& );
Singleton& operator=( Singleton const& );
public:
static Singleton const& instance();
};
そして実装では:
Singleton const* Singleton::ourInstance = &Singleton::instance();
Singleton const&
Singleton::instance()
{
if ( ourInstance == NULL ) {
ourInstance = new Singleton;
}
return *ourInstance;
}
スレッド化が開始されるとスレッドは何も変更しないため、ロックは必要ありません。
シングルトンが変更可能な場合、シングルトンへのすべてのアクセスを保護する必要があります。上記のようなことを (
const
明らかに なしで) 実行し、ロックをクライアントに任せることもできますが、そのような場合は、instance
関数をロックしstd::shared_ptr
、取得したロックを解放するデリータを使用して を返すことをお勧めします。instance
関数で。次のようなものがうまくいくと思います(ただし、実際に必要になったことがないため、試していません):
class Singleton
{
static Singleton* ourInstance;
static std::mutex ourMutex;
class LockForPointer
{
public:
operator()( Singleton* )
{
Singleton::ourMutex.unlock();
}
};
class LockForInstance
{
bool myOwnershipIsTransfered;
public:
LockForInstance
: myOwnershipIsTransfered( false )
{
Singleton::ourMutex.lock();
}
~LockForInstance()
{
if ( !myOwnershipIsTransfered ) {
Singleton::ourMutex.unlock();
}
}
LockForPointer transferOwnership()
{
myOwnershipIsTransfered = true;
return LockForPointer();
}
};
public:
static std::shared_ptr<Singleton> instance();
};
そして実装:
static Singleton* ourInstance = NULL;
static std::mutex ourMutex;
std::shared_ptr<Singleton>
Singleton::instance()
{
LockForInstance lock;
if ( ourInstance == NULL ) {
ourInstance = new Singleton;
}
return std::shared_ptr<Singleton>( ourInstance, lock.transferOwnership() );
}
このようにして、null のチェックとデータへのアクセスに同じロックが使用されます。