1

私は今ゲームエンジンをプログラミングしています。私にとって最も難しい部分は、メモリ管理です。私は可能な限り多くの最適化を行ってきましたが(すべてのフレームがカウントされるためですよね?)、これに取り組む最善の方法は、スタックとプールのアロケータを使用してリソース管理を行うことであることに気付きました。問題は、これらのアロケータによってメモリ管理されるシングルトンクラスを作成する方法がわからないことです。

私のシングルトンはマネージャーなので、実際にはかなり大きく、それらのメモリ管理は私のゲームの起動速度にとって重要です。alloc()基本的に、タイプを返すアロケータの関数を呼び出してvoid*、この割り当てられたスペースにシングルトンを作成できるようにしたいと考えています。

私は、各シングルトンクラスにstatic booleancalledを配置し、 trueの場合instantiatedにコンストラクターを返すことを考えてきました。これは機能しますか?NULLinstantiated

4

2 に答える 2

3

これが、シングルトンがダメだと誰もが考える理由です。彼らは恐ろしく吸う。これは彼らのサックのほんの一面であり、アプリケーション全体をサックダウンします。

問題を解決するには:Suckletonsを使用しないでください。

于 2012-06-28T01:37:57.073 に答える
1

さて、私は自分の経験を共有することによってこれに答えます。通常、クラスにすべての独自の機能を持たせたいのですが、後でわかりました。これには、特異なオブジェクトのインスタンスを他のコードに提供するためのファクトリメソッドが必要になる場合があります。インスタンスは、状態などを維持するために実際には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シングルトンがスレッドセーフな方法で実装されることが保証されます。

于 2012-06-28T16:41:16.660 に答える