饭后温柔

汉堡与老干妈同嚼 有可乐味
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

ogre的singleton与loki的singleton

Posted on 2011-10-24 00:23  饭后温柔  阅读(1071)  评论(0编辑  收藏  举报

编辑器使用ogre的singleton和loki的singleton,遇到了一个有趣的问题.

问题是关以一个bug的.

典型的qt的main函数如下:

int main(int argc, char *argv[])
{

QApplication a(argc, argv);
XEditor w;
w.show();
return a.exec();
}

QApplication是每个qt程序必须的.他应该最先构造,最后析构.上面代码没有问题,注意QApplication和XEditor(自定义ui类)都是在栈上定义的.

写的过程中对XEditor使用了loki的singleton类,主要是为了与其他类交互方便:

int main(int argc, char *argv[])
{

QApplication a(argc, argv);
XEditor::instance()::show();
return a.exec();
}

之后陆续添加了一些widget,list等控件,未发现问题.之后添加toolbar时,出现问题了,关闭程序时总会abort,发生在toolbar析构时.因为对qt并不熟悉,以为是自己写toolbar时错了,但仔细检查了自己qt控件的相关代码,未发现问题.而loki的singleton是很久之前加了进去,未想到这方面.

程序将近写完时,再跟这个问题.发现析构时toobar的parent已经为空了.综合Google的一些搜索确定了是QApplication提前析构了.参考项目使用的是ogre的singleton类,未出现问题.然后才想起来loki中的singleton类,是在运行期new出了实例:

    inline T& SingletonHolder<T, CreationPolicy, 
LifetimePolicy, ThreadingModel, MutexPolicy>::Instance()
{
if (!pInstance_)
{
MakeInstance();
}
return *pInstance_;
}

于是在main函数退出时,栈上的对象要先于堆上的对象析构.QApplication先析构,然后XEditor才析构,导致出现错误.这个错误比较隐蔽,并不一定发生abort.自己的项目是加入了toolbar才发现问题.

之前参考的项目对XEditor使用了ogre的singleton类.Ogre::singleton是在构造函数中就给静态指针赋值了.并且是本身的this指针.因此要求使用该类时必须先有一个实例.而第一段代码中就自然而然在栈上定义XEditor.

        Singleton( void )
{
assert( !ms_Singleton );
ms_Singleton = static_cast< T* >( this );
}

ogre与loki对singleton的static指针赋值的阶段不同.导致的区别是当在栈上定义一个实例后,ogre的方式可以直接调用该类了.而loki的实现,却会自己又在堆中生成一个实例.然后才针对这个堆上的实例进行调用.

诚然loki的实现不需要用户使用之前必须定义一个实例,但在某些情况下(这个例子),会导致语义分离(我需要一个栈上的对象,但给我的是一个堆上的对象,且浪费了).loki的singleton的很多优点都有赖于类实例在堆上生成(主要是关于生命周期的管理).

如果不希望把出现2个singleton类实现,可以把QApplication也改为在堆上定义.

一个singleton的实现,其静态指针是在构造函数中生成还是动态需求时生成,其区别能在这里遇到,之前并没想到.