借鉴了剑指offer书上写的和一个博客:C++单例模式。自己做一个简单的总结。
- 什么是单列模式?
只能有一个实例化的对象的类。那么如何做到只有一个实例化对象呢?
构造函数一般定义在public之中,你也可以定义在protected和private之中,这样的话就没有办法进行外部实例化。有的时候, 会要求禁止用户创建类的实例就会这么用的。
- 构造函数不能从外部调用 ---> 构造函数为私有或保护
- 专门设置一个接口供外部调用,但是多次调用的返回值必须是同一个对象 ---> 静态对象,同时接口必须是静态成员函数
class csingleton {
private:
csingleton() {}
static csingleton* p;
public:
static csingleton* getInstance() {
if (p == NULL) {
p = new csingleton();
}
return p;
}
};
csingleton* csingleton::p = NULL;
注意点:
- 当p == NULL的时候,是调用一次构造函数而不是直接返回。
if(p==NULL) return new csingleton();//错误
- 为了封装性,静态成员指针应该私有化。
不过上面这个也只是一个单线程下没问题的单列模式,如果是多线程环境下,多个线程同时创建singleton对象,并且指针为NULL呢?那不是发生了错误吗?所以要对临界区进行保护,加锁。
//多线程下的单列模式--->仅仅多了加锁
class singleton_pthread {
private:
singleton_pthread() {
}
static singleton_pthread* p;
static pthread_mutex_t mtx;
public:
static singleton_pthread* getInstance() {
if (p == NULL) {
pthread_mutex_lock(&mtx);
p = new sigleton();
pthread_mutex_unlock(&mtx);
}
return p;
}
};
singleton_pthread* singleton_pthread::p = NULL;
pthread_mutex_t singleton_pthread::mtx = PTHREAD_MUTEX_INITIALIZER;
/*
PTHREAD_MUTEX_INITIALIZER 用在静态类型的互斥量中,
而且应该在互斥量定义的时候就用 PTHREAD_MUTEX_INITIALIZER 进行初始化,
否则用 pthread_mutex_init 进行初始化。
pthread_mutex_t mutex;
pthread_mutex_init(&mutex,NULL); //NULL为默认的互斥锁
*/
其实加锁是耗时的操作,但是这个....感觉写到这面试差不多了。不过上述两种单线程、多线程的单列模式都是属于懒汉模式——就是有需要的时候才创建,比如我们一开始都只是把对象指针初始化NULL,如果采用饿汉模式——直接在指针初始化的时候就创造一个实例化对象。而且直接创建出来了就不存在资源抢夺,也就不用加锁了。
class singleton{
private:
singleton(){}
static singleton* p;
public:
singleton* getInstance(){
return p;
}
}
singleton* singleton::p = new singleton();//p是CSingleton的成员,它是可以调用构造函数的