实现单例不难,最简单的方式如下:
class SingleTon
{
public:
static SingleTon & GetInstance()
{
static SingleTon;
return SingleTon;
}
protected:
SingleTon()
{
}
SingleTon(const SingleTon &){}
};
再或者返回指针类型,new出单例对象,此时就应该考虑线程安全性问题了,常有的方式是doule check ,当GetInstance 方法中检测到instance指针为空时,需要加锁,然后再次判断是否为空,此时还为空再创建instance对象,避免不检查出现和其他线程重复创建这个类的对象,完整代码如下:
SingleTon.h
//
// SingleTon.hpp
// CodeTest
//
// Created by xiangzhenwei on 2019/4/20.
// Copyright © 2019年 xiangzhenwei. All rights reserved.
//
#ifndef SingleTon_hpp
#define SingleTon_hpp
#include <stdio.h>
#include <pthread.h>
template <typename T>
class Singleton
{
public:
static T * GetInstance();
protected:
Singleton()
{
printf("Singleton constcut called...\n");
};
~ Singleton()
{
printf("Singleton desconstcut called...\n");
};
protected:
class GC
{
public:
GC()
{
printf("GC constcut Begin call!\n");
}
~GC()
{
printf("GC Desctuct begin call...\n");
if(m_instance)
{
delete m_instance;
}
}
};
protected:
static GC m_gc;
private:
Singleton(const Singleton &) {}
Singleton & operator= (const Singleton &){}
static T * m_instance;
static pthread_mutex_t m_metux;
};
//保护类型的单例构造函数,友元访问
#define SPECAIL_SINGLETON(classType) friend class Singleton<classType>;
//单例模板类特化,垃圾回收期指定
#define SPECAIL_SINGLETON_GC(T) template Singleton<T>::Singleton<T>::GC Singleton<T>::Singleton<T>::m_gc;
#define IMPL_SINGLE_TON
#include "SingleTon.cpp"
#endif /* SingleTon_hpp */
SingleTon.cpp
//
// SingleTon.cpp
// CodeTest
//
// Created by xiangzhenwei on 2019/4/20.
// Copyright © 2019年 xiangzhenwei. All rights reserved.
//
#ifdef IMPL_SINGLE_TON
template <typename T>
T * Singleton<T>::m_instance = NULL;
template <typename T>
pthread_mutex_t Singleton<T>::m_metux = PTHREAD_MUTEX_INITIALIZER;
template <typename T>
typename Singleton<T>::GC Singleton<T>::m_gc;
template <typename T>
T * Singleton<T>::GetInstance()
{
if(m_instance == NULL)
{
pthread_mutex_lock(&m_metux);
if(m_instance == NULL)
{
m_instance = new T();
}
pthread_mutex_unlock(&m_metux);
}
return m_instance;
}
#endif
以上使用方式使用了模板函数,并实现了单例的垃圾自动回收
#define SPECAIL_SINGLETON_GC(T) template Singleton<T>::Singleton<T>::GC Singleton<T>::Singleton<T>::m_gc;
上面这段代码是对模板单例方法垃圾回收期静态定义的一个宏实现,例如定义了一个UserManager单例,则需要在UserManager实现的cpp加上一行代码,如下,才能确保垃圾回收期静态对象在程序启动的时候被构造,程序退出的时候被析构,调用单例的释放函数。
SPECAIL_SINGLETON_GC(UserManager)
定义了以上的模板类,下面来特化一下单例模板类:
//
// main.cpp
// CodeTest
//
// Created by xiangzhenwei on 2019/4/20.
// Copyright © 2019年 xiangzhenwei. All rights reserved.
//
#include <iostream>
#include "SingleTon.h"
#include <string>
#include <vector>
class ShapeMgr
{
SPECAIL_SINGLETON(ShapeMgr)
private:
ShapeMgr()
{
printf("ShapeMgr constuct...\n");
}
ShapeMgr(const ShapeMgr &) {}
public:
~ShapeMgr()
{
printf("ShapeMgr destruct\n");
}
void SayType()
{
printf("ShapeMgr SayType called,this->ptr=%p\n",this);
}
};
class PersonMgr
{
SPECAIL_SINGLETON(PersonMgr)
private:
PersonMgr()
{
printf("PersonMgr constuct...\n");
}
PersonMgr(const PersonMgr &) {}
public:
~PersonMgr()
{
printf("PersonMgr destruct\n");
}
void SayType()
{
printf("PersonMgr SayType called,this->ptr=%p\n",this);
}
};
SPECAIL_SINGLETON_GC(ShapeMgr)
SPECAIL_SINGLETON_GC(PersonMgr)
SPECAIL_SINGLETON_GC(int)
SPECAIL_SINGLETON_GC(double)
SPECAIL_SINGLETON_GC(float)
SPECAIL_SINGLETON_GC(std::string)
SPECAIL_SINGLETON_GC(std::vector<int>)
int main(int argc, const char * argv[]) {
// insert code here...
std::cout << "Hello, World!\n";
ShapeMgr * p1 = Singleton<ShapeMgr>::GetInstance();
if (p1 == NULL) {
printf("Bad instance returned\n");
return -1;
}
p1->SayType();
ShapeMgr * p2 = Singleton<ShapeMgr>::GetInstance();
p2->SayType();
PersonMgr * p3 = Singleton<PersonMgr>::GetInstance();
if (p3 == NULL) {
printf("Bad instance returned\n");
return -1;
}
p3->SayType();
PersonMgr * p4 = Singleton<PersonMgr>::GetInstance();
p4->SayType();
int * pInt = Singleton<int>::GetInstance();
*pInt = 121231;
int * pb = Singleton<int>::GetInstance();
std::vector<int> * pv = Singleton<std::vector<int> >::GetInstance();
pv->push_back(1);
pv->push_back(2);
std::vector<int> * pv23 = Singleton<std::vector<int> >::GetInstance();
return 0;
}
在ShapeMgr特化时,需要加一行友元申明代码:
SPECAIL_SINGLETON(ShapeMgr)
保证GetInstance方法能够调用ShapeMgr的构造函数,因为单例类的构造函数我们通常是定义为保护或者私有的。
下面是以上代码编译运行的截图:
以上是个人思考和实践,当然GetInstance 中double check也不是唯一方法,只是也可以使用其他方式,例如:
int pthread_once(pthread_once_t *, void (* _Nonnull)(void)); 实现了一个进程只调用一次的方法,pthread_once传入我们单例初始化函数,也是可以的,大致代码如下:
SingleTon * SingleTon::m_instance = NULL;
pthread_once_t SingleTon::once_control = PTHREAD_ONCE_INIT;
void init_singleton()
{
if(m_instance ==NULL)
{
m_instance = new Singleton();
}
}
SingleTon * GetInstance()
{
if(m_instance == NULL)
{
pthread_once(&once_control,init_singleton);
}
return m_instance;
}