内存管理的C ++单例

时间:2012-06-28 01:28:43

标签: c++ memory memory-management

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

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

我一直在考虑在每个单例类中放置static boolean instantiated,如果NULL为真,则让构造函数返回instantiated。这会有用吗?

2 个答案:

答案 0 :(得分:4)

这就是为什么每个人都认为单身人士很糟糕。他们可怕地吮吸。这只是他们吮吸的一个方面,它会用它来吸取你的整个应用程序。

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

答案 1 :(得分:0)

好的,我将通过分享自己的经验回答这个问题。通常我希望一个类具有所有自己的功能,然后实现这可能需要一个工厂方法来为其他代码提供一个单独的对象实例。该实例实际上应该只定义一次以维持状态等。因此,这就是我对没有将所有初始化包装到构造中的类所做的。我不想用singletonsuxness混乱现有的类,所以我创建了一个工厂包装类来帮助我。你可以使用Myer的单例模式,这是优雅的,并通过让静态局部变量的实现(依赖于静态本地init的编译器实现,这并不总是一个好主意)来封装锁定来处理锁定,但如果你喜欢问题就来了我希望您的对象默认构造,以便您可以轻松地在它们上使用STL向量等,然后在它们上调用某种类型的初始化,可能将参数传递给此方法,使它们更重。

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单例将以线程安全的方式实现,只使用本地静态变量