C++单例模式简复习:饿汉式,懒汉式线程安全

单例模式,顾名思义,即一个类只有一个实例对象。

饿汉式写法

饿汉式写法全局只有一个已经创建好的静态对象,每次要用时就返回这个对象的引用就行,饿汉式在多线程里面同时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;
}

运行如图
这次对前面的知识重新复习一下收益良多,大家一起学习进步;

猜你喜欢

转载自blog.csdn.net/qq_40861091/article/details/95588014