C++——自動Singletonの実現
このブログは自動Singletonの設計モデルの実現を実現し,通常のSingletonの実現に比べて,この方法はより簡単で柔軟である.
Singleton設計モード
単一モードは、プロジェクトにおいて重要な設計モードであり、1つのオブジェクトがプロジェクトに1つのインスタンスしか存在しないことを保証します.ゲームでは、例えばTexture Manager、Data Tableといったものは、ゲームが終了するまでゲームの開始時からインスタンスを作成しているはずです.
Singletonは、プロジェクト内のグローバル・オブジェクトとして扱われることが多いため、特定のトランザクションに属さなければならないオブジェクトに比べて、グローバル・オブジェクトのSingletonは効率的で簡便であることが多い.そうでなければ、次のような方法でTextureManagerを取得すると、クラッシュすることがあります.
もちろん、外部接続のグローバル範囲のg_として宣言することができます.TextureMgrがアクセスします.これは確かに便利ですが、グローバルオブジェクトの作成と破棄の順序は実行時の状況に依存するため、移植可能なプロジェクトでは予測できないため、効果はあまりよくありません.
従来の方法
教科書では、Singletonの管理は通常次のようになります.
もちろん便宜上、テンプレートやマクロを使用しているプロジェクトもありますが、本質は同じです.最初の呼び出しでインスタンス化し、プログラムの解釈で破棄します.
しかし、この方法には、リソースの破棄を制御できないという欠点があります.つまり、プログラムが終了したときに解放されなければなりません.言い換えれば、私たちは資源に対するコントロールの程度がまだ足りない.私たちがゲームを実行している間に一部を閉じたいとすれば、このようなやり方は明らかに実現できません.
言い換えれば、このリソースを追跡する必要があります.つまり、そのポインタを見つける必要があります.
次のような方法があります.
上記の方法を使用すれば、いつでもTextureMgrを作成および破棄することができ、Singletonへのアクセスも容易である.
しかし、Singletonを追跡するためのコードが各クラスに追加される必要があり、コードが煩雑に見える点も不便です.
自動Singletonの実装
自動Singletonは、テンプレートを使用してSingletonポインタを自動的に定義し、ポインタの設定、クエリー、クリアを完了します.また、assertを使用してSingletonを複数回インスタンス化していないことを確認することもできます.
しかし最も重要な点は、このクラスから派生するだけでSingletonの機能を得ることができることです.
コードは次のとおりです.
上のコードで疑問になりやすいのは,構造関数におけるoffset論理である.これはオブジェクトの比較とタイプの変換に関する問題で、別のブログでは、転送ゲートについても言及しています.
クラスをSingleton化する必要がある場合は、Singletonから公開継承する必要があります.この方法はクラスのサイズに影響を及ぼさず、自動関数呼び出しを追加するだけです.
もちろん、使用前に対応するMyClassがインスタンス化されていることを確認します.インスタンス化されると追跡されます.これにより、
<全文完了>
Singleton設計モード
単一モードは、プロジェクトにおいて重要な設計モードであり、1つのオブジェクトがプロジェクトに1つのインスタンスしか存在しないことを保証します.ゲームでは、例えばTexture Manager、Data Tableといったものは、ゲームが終了するまでゲームの開始時からインスタンスを作成しているはずです.
Singletonは、プロジェクト内のグローバル・オブジェクトとして扱われることが多いため、特定のトランザクションに属さなければならないオブジェクトに比べて、グローバル・オブジェクトのSingletonは効率的で簡便であることが多い.そうでなければ、次のような方法でTextureManagerを取得すると、クラッシュすることがあります.
GetApp()->GetServices()->GetGui()->GetTextureMgr();
もちろん、外部接続のグローバル範囲のg_として宣言することができます.TextureMgrがアクセスします.これは確かに便利ですが、グローバルオブジェクトの作成と破棄の順序は実行時の状況に依存するため、移植可能なプロジェクトでは予測できないため、効果はあまりよくありません.
従来の方法
教科書では、Singletonの管理は通常次のようになります.
TextureMgr& GetTextureMgr()
{
static T s_Singleton;
return s_Singleton;
}
もちろん便宜上、テンプレートやマクロを使用しているプロジェクトもありますが、本質は同じです.最初の呼び出しでインスタンス化し、プログラムの解釈で破棄します.
しかし、この方法には、リソースの破棄を制御できないという欠点があります.つまり、プログラムが終了したときに解放されなければなりません.言い換えれば、私たちは資源に対するコントロールの程度がまだ足りない.私たちがゲームを実行している間に一部を閉じたいとすれば、このようなやり方は明らかに実現できません.
言い換えれば、このリソースを追跡する必要があります.つまり、そのポインタを見つける必要があります.
次のような方法があります.
class TextureMgr
{
static TextureMgr* ms_Singleton;
public:
TextureMgr()
{
ms_Singleton = this;
// ...
}
~TextureMgr()
{
ms_Singleton = NULL;
// ...
}
TextureMgr& GetSingleton()
{
return (*ms_Singleton);
}
};
上記の方法を使用すれば、いつでもTextureMgrを作成および破棄することができ、Singletonへのアクセスも容易である.
しかし、Singletonを追跡するためのコードが各クラスに追加される必要があり、コードが煩雑に見える点も不便です.
自動Singletonの実装
自動Singletonは、テンプレートを使用してSingletonポインタを自動的に定義し、ポインタの設定、クエリー、クリアを完了します.また、assertを使用してSingletonを複数回インスタンス化していないことを確認することもできます.
しかし最も重要な点は、このクラスから派生するだけでSingletonの機能を得ることができることです.
コードは次のとおりです.
#include <cassert>
template < typename T>
class Singleton
{
static T * ms_Singleton;
public :
Singleton ()
{
assert (! ms_Singleton );
int offset = (int )( T*) 1 - ( int )(Singleton < T>*)( T *)1 ;
ms_Singleton = ( T *)( (int ) this + offset );
}
~Singleton ()
{
assert ( ms_Singleton );
ms_Singleton = NULL ;
}
static T & GetSingleton ()
{
assert ( ms_Singleton );
return (* ms_Singleton );
}
static T * GetSingletonPtr ()
{
return ms_Singleton;
}
};
template < typename T >
T * Singleton < T>:: ms_Singleton = 0 ;
上のコードで疑問になりやすいのは,構造関数におけるoffset論理である.これはオブジェクトの比較とタイプの変換に関する問題で、別のブログでは、転送ゲートについても言及しています.
クラスをSingleton化する必要がある場合は、Singletonから公開継承する必要があります.この方法はクラスのサイズに影響を及ぼさず、自動関数呼び出しを追加するだけです.
もちろん、使用前に対応するMyClassがインスタンス化されていることを確認します.インスタンス化されると追跡されます.これにより、
MyClass::GetSingleton ()
手法を用いてこのオブジェクトを得ることができる.<全文完了>