单例模式,顾名思义,即一个类只有一个实例对象。
饿汉式写法
饿汉式写法全局只有一个已经创建好的静态对象,每次要用时就返回这个对象的引用就行,饿汉式在多线程里面同时getInstance()去获取这个对象的时候,是不存在安全问题的,饿汉式写法如下:
#include<iostream>
using namespace std;
class Student
{
private:
Student():age(99){
cout << "e_han construct! age="<<age << endl; };
~Student(){
cout << "e_han destory!" << endl; };
int age;
Student(const Student &);//把这个拷贝构造和下一行的操作符重载设为私有,没必要实现
Student& operator=(const Student &);//这样就能防止对象被拷贝
static Student myInstance; // 单例对象在这里!
public:
static Student* getInstance()
{
return &myInstance;//返回对象的引用
}
void printAge()
{
cout<<this->age<<endl;
}
};
//静态对象记得初始化哦,不然会报错undefined reference to `Student::myInstance'
Student Student::myInstance;
int main()
{
Student *stu_1=Student::getInstance();
stu_1->printAge();
//对象是全局一开始就建立好的,两个函数获取到的是同一个对象
Student *stu_2=Student::getInstance();
stu_2->printAge();
return 0;
}
懒汉式写法1-不考虑线程安全
懒汉式和上面饿汉式的区别是:饿汉式是程序运行时一开始就构造了一个全局对象,要用的时候去拿就行了。而懒汉式是第一次要用到的时候才去New生成这个对象(所以比较懒),之后获取的也是第一次New构造出来的对象指针。
同时我们的指针new完之后,在程序结束时,我们需要释放掉这个指针指向的内存,这里同比较常见方法:定义一个内部类,这个内部类析构时,,辅助他释放指针内存
#include<iostream>
using namespace std;
class Student
{
private:
Student():age(99){
cout << "lan_han construct!this age="<<age << endl; };
~Student(){
cout << "lan_han destory!" << endl; };
Student(const Student &);//设置拷贝构造和操作符=重载防止对象拷贝
Student& operator=(const Student &);
int age;
static Student *myInstance; // 这里是对象指针,不是一个实例化对象了
public:
static Student* getInstance()
{
if(myInstance==nullptr)
{
myInstance=new Student();
}
return myInstance;//返回对象指针
}
void printAge()
{
cout<<this->age<<endl;
}
private:
// 定义一个内部类
class CGarbo{
public:
CGarbo(){
};
// 定义一个内部类的静态对象
static CGarbo m_garbo;
~CGarbo()//对象程序结束析构时对主类指针释放内存
{
if (nullptr != myInstance)
{
delete myInstance;
myInstance = nullptr;
}
}
};
};
//记得要初始化静态对象,里面只是定义了他,没有分配内存空间
Student* Student::myInstance=nullptr;
Student::CGarbo Student::m_garbo;
int main()
{
Student *stu_1=Student::getInstance();
stu_1->printAge();
Student *stu_2=Student::getInstance();
stu_2->printAge();
return 0;
}
懒汉式线程安全写法
不知道大家注意到懒汉式上面的这一段代码了吗
static Student* getInstance()
{
if(myInstance==nullptr)
{
myInstance=new Student();
}
return myInstance;//返回对象指针
}
这段代码在多线程中,比如两个线程,刚好同时执行到if(myInstance==nullptr)的话,两个线程都是判断myInstance为空,然后就会两次new操作,这样就生成了两个对象,就不是单例模式了。
但是我们可以加入#include<mutex>,然后生成mutex mylock锁,在执行到这段的时候
static Student* getInstance()
{
if(myInstance==nullptr)
{
mylock.lock();//加锁
myInstance=new Student();
mylock.unlock();//解锁
}
return myInstance;//返回对象指针
}
这样加锁之后,能确保只有一个对象,但是这样还不够好,如果线程非常多的话,频繁加锁解锁是效率很低下的。所以对这个懒汉式进行一定的改造
全局代码如下:
#include<iostream>
#include<thread>//多线程头文件
#include<mutex>
using namespace std;
//创建全局锁
mutex mylock;
class Student
{
private:
Student():age(88){
cout << "construct! this age="<<age << endl; };
Student(const Student &);
Student& operator=(const Student &);
~Student(){
cout << "destory!" << endl; };
static Student *myInstance;
int age;
public:
static Student * getInstance()
{
if (nullptr == myInstance)
{
lock_guard<mutex> lock(mylock);
if (nullptr == myInstance)
{
myInstance = new Student();
}
}
return myInstance;
}
void printAge()
{
cout<<this->age<<endl;
}
private:
// 定义一个内部类
class CGarbo{
public:
CGarbo(){
};
~CGarbo()
{
if (nullptr != myInstance)
{
delete myInstance;
myInstance = nullptr;
}
}
};
// 定义一个内部类的静态对象
static CGarbo m_garbo;
};
Student * Student::myInstance = nullptr;
Student::CGarbo Student::m_garbo;
int main()
{
Student * ct1 = Student::getInstance();
ct1->printAge();
Student * ct2 = Student::getInstance();
ct2->printAge();
return 0;
}
这次对前面的知识重新复习一下收益良多,大家一起学习进步;