1

我现在正在编写游戏引擎。对我来说最难的部分是内存管理。我一直在进行尽可能多的优化(因为每一帧都很重要,对吗?)并意识到解决这个问题的最佳方法是使用堆栈和池分配器进行资源管理。问题是,我不知道如何创建一个由这些分配器管理的内存的单例类。

我的单例是管理器,所以它们实际上相当大,它们的内存管理对于我的游戏的启动速度很重要。我基本上希望能够调用我的分配器的alloc()函数,它返回 type void*,并在这个分配的空间中创建我的单例。

我一直在考虑在每个单例类中static boolean调用一个,如果为真则让构造函数返回。这行得通吗?instantiatedNULLinstantiated

4

2 回答 2

3

这就是为什么每个人都认为单身人士很烂的原因。他们糟透了。这只是他们糟糕的一个方面,它会影响你的整个应用程序。

为了解决您的问题:不要使用 Suckleton。

于 2012-06-28T01:37:57.073 回答
1

好的,所以我将通过分享我自己的经验来回答这个问题。通常我希望一个类拥有它自己的所有功能,然后意识到这可能需要一个工厂方法来为其他代码提供我的对象的一个​​实例,该实例是单数的。实例实际上应该只定义一次以维护状态等。因此,这就是我为没有将所有初始化包装到构造中的类所做的。我不想让我现有的类因单例而混乱,所以我创建了一个工厂包装类来帮助我解决这个问题。您可以使用 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 回答