现在代码中越来越多的使用单体类,而我们通常的编写代码的方式是:
在A.h文件中:
class CTest
{
public:
static CTest* _ins;
static CTest* Ins()
};
在A.cpp中:
CTest* CTest::_ins = NULL;
CTest* CTest::Ins()
{
if ( !_ins )
{
try
{
_ins = new CTest();
}
catch(...)
{
return NULL;
}
}
return _ins;
}
而实际上,上面的代码通过valgrind检查内存泄漏的时候,会告诉你内存still reachable,虽然实际上当进程退出的时候,这些内存是实际释放掉了,但是还是多少会对内存泄漏的定位产生影响,而且也不符合谁申请谁释放的原则。
我们可以简单的使用stl的智能指针解决这个问题,即代码更改如下:
在A.h文件中:
class CTest
{
public:
static auto_ptr<CTest> m_auto_ptr;
static CTest* _ins;
static CTest* Ins();
};
在A.cpp中:
auto_ptr<CTest> CTest::m_auto_ptr;
CTest* CTest::_ins = NULL;
CTest* CTest::Ins()
{
if ( !_ins )
{
try
{
_ins = new CTest();
}
catch(...)
{
return NULL;
}
}
return _ins;
}
CTest::CTest()
{
m_
auto_ptr = auto_ptr<CTest>(this);
}
OK,这样valgrind的内存检查就可以通过了,但是实际上构建一个单体类要比我们的代码复杂的多,比如要考虑copy构造函数的问题,因为有可能有人会这样使用 CTest = *CTest::Ins(); 而这样明显是不可以的,还有就是肯定不能允许别人delete掉唯一的ins,所以析构函数应该为private或者protected等等,还有构造函数应该为private等等。
在这里贴出一份比较合理的代码,其实就是我写的load_template.vim插件的一个标准模板。
A.h
#ifndef _X_H_
#define _X_H_
#include <iostream>
#include <string>
#include <vector>
#include <map>
using namespace std;
class CTest
{
private:
static auto_ptr<CTest> m_auto_ptr;
static CTest * m_ins;
public:
static CTest * Ins();
protected:
CTest();
CTest(const CTest&);
virtual ~CTest();
friend class auto_ptr<CTest>;
};
#endif
A.cpp
#include "x.h"
CTest* CTest::m_ins = NULL;
auto_ptr<CTest> CTest::m_auto_ptr;
CTest::CTest()
{
m_auto_ptr = auto_ptr<CTest>(this);
}
CTest::~CTest()
{
}
CTest* CTest::Ins()
{
if ( m_ins == NULL)
m_ins = new CTest();
return m_ins;
}
GuoJing on #
文章不错,不过我觉得ins还是写全称比较好吧,虽然能理解,然是总在后文感觉不太好读。。可能这是c/c++的习惯吧。。
Reply
Dante on #
呃,看来我简写的有些过火了……呃,要改要改……代码可读性很成问题呢……
Reply
thawk on #
这种写法没有考虑到在全局或静态变量中使用的问题。如果有人在全局或静态变量中使用CTest,那么在调用CTest::Ins()时,CTest::m_ins可能还没有初始化,这会有问题。
一个解决方案就是把m_ins移到Ins()中,作为Ins()内部的静态变量,C++标准有规定在进入Ins()时,其内部静态变量一定会被初始化。
singleton是一个看起来简单,实现起来很复杂的东西 :(
Reply
Dante on #
有道理……,都是static的话确实有初始化先后的问题,我再考虑一下作为内部变量会不会有什么问题~
Reply
alexandercer on #
记得effect c++上,作者就是在ins函数里面使用静态局部变量来实现的.
Reply
Dante on #
……我家里那本effective c++,早知就好好看看了……
不过我现在确实改为函数内部实现了,昨天问了一下,确实有个项目组因为这个singleton的static变量放在类外边引发问题的。
Reply
alexandercer on #
事实上呢,不同系统采用了不同的singleton模式,记得orge里面的就是使用模板...ace里面更加的诡异....还是函数内实现最直观方便理解....
Reply
jackaldire on #
用一个类似MFC的宏来处理更方便
#define DEFINE_SINGLETON(Singleton)\
public:\
static Singleton& Instance();\
private:\
Singleton();\
Singleton(const Singleton&);\
Singleton& operator=(const Singleton&);\
~Singleton();
#define IMPLEMENT_SINGLETON(Singleton)\
Singleton & Singleton::Instance() {\
static Singleton obj;\
return obj;\
}
单件确实是一个想法简单实现困难的东西,即使采用局部静态变量还是有线程安全的问题
Reply
Dante on #
嗯啊,这种方式确实不错哈~~
Reply