23种设计方法c++实现(5)单例模式

单例模式:

这是最简单的模式,就是在程序中,对于某个类只允许实例化一个对象。

单例类负责自己的实例化,并提供调用它的接口。

UML结构图

设计要点

  • 构造函数Singleton()设计为private,这样就只能自己负责实例化自己。
  • 定义一个private static Singleton(饿汉模式),或者定义一个private static Singleton * (懒汉模式)。这就要求在程序开始前生成一个Singleton,或者Singleton *
  • 定义一个 static public 函数,(例如:GetInstance()),这是让外部对单例进行操作的接口。

下面的代码需要对static在类中的使用有一定的了解,请参考这个文章:https://blog.csdn.net/shaochuang1/article/details/96181430

代码

饿汉模式

#include <iostream>
using namespace std;

class Singleton
{
  private:
    Singleton(){
        cout << "构造" << endl;
        num = 10;
    }
    ~Singleton(){
        cout << "析构" << endl;
    }
    int num;
    static Singleton locla_s;
  public:
    static Singleton *getInstance()
    {
        return &locla_s;
    }
    void Print()
    {
    	std::cout << num << std::endl;
    }	
};

Singleton Singleton::locla_s;//值得注意的地方

int main()
{
    Singleton* P_Singleton = Singleton::getInstance();
    P_Singleton->Print();
	return 0;
}

对于饿汉模式来说,程序一开始就需要将单例对象给实例化出来,无论我们需不需要。这对我们的内存是不友好的,如果当我们要用这个单例对象的时候,再来实例化它,就会很好。

懒汉模式

#include <iostream>
using namespace std;

class Singleton
{
  private:
    static Singleton *local_instance;
    Singleton(){cout  << "构造" << endl;}
    ~Singleton(){cout  << "析构" << endl;}

  public:
    static Singleton *getInstance()
    {
        if (local_instance == nullptr)
        {
            local_instance = new Singleton();
            cout << "new 新空间" << endl;
        }
        else
        {
            cout << "空间不变" << endl;
        }
        
        return local_instance;
    }
    static void delete_local()
    {
        delete local_instance;
        local_instance = nullptr;
    }
};

Singleton * Singleton::local_instance = nullptr;//值得注意


int main() 
{    
    Singleton * s1 = Singleton::getInstance();
    Singleton * s2 = Singleton::getInstance();
    Singleton::delete_local();
    return 0;
}

我们的懒汉模式就是在程序需要的时候,再来实例化单例对象。如果在多线程中这个懒汉模式也会出问题。如果两个线程同时构造单例对象,这个时候就会出现两个单例对象,这就违背了单例模式的设计原则啦。

适用于多线程中的懒汉模式

#include <iostream>
#include <mutex>
using namespace std;

class Singleton
{
  private:
    static Singleton *local_instance;
    static mutex my_mutex;
    Singleton(){cout  << "构造" << endl;}
    ~Singleton(){cout  << "析构" << endl;}

  public:
    static Singleton *getInstance()
    {
        std::lock_guard<std::mutex> my_lock_guard(my_mutex);
		if (local_instance == nullptr)
        {
            local_instance = new Singleton();
            cout << "new 新空间" << endl;
        }
        else
        {
            cout << "空间不变" << endl;
        }
        
        return local_instance;
    }
    static void delete_local()
    {
        delete local_instance;
        local_instance = nullptr;
    }
};

Singleton * Singleton::local_instance = nullptr;//值得注意
mutex Singleton::my_mutex;

int main() 
{    
     Singleton * s1 = Singleton::getInstance();
     Singleton * s2 = Singleton::getInstance();
     Singleton::delete_local();
    return 0;
}

通过观察你会发现,每次调用static Singleton *getInstance()这个函数的饿时候,都需要触发锁,但是实际情况是,只有第一次实例化单例类的时候才需要触发锁。每次都触发锁就使得代码的效率十分不好。这个时候我们就需要,双重锁定。

双重锁定

#include <iostream>
#include <mutex>
using namespace std;

class Singleton
{
  private:
    static Singleton *local_instance;
    static mutex my_mutex;
    Singleton(){cout  << "构造" << endl;}
    ~Singleton(){cout  << "析构" << endl;}

  public:
    static Singleton *getInstance()
    {    
        if(local_instance == nullptr)
        {
            std::lock_guard<std::mutex> my_lock_guard(my_mutex);
		    if (local_instance == nullptr)
            {
                local_instance = new Singleton();
                cout << "new 新空间" << endl;
            }
        }
        else
        {
            cout << "空间不变" << endl;
        }
        
        return local_instance;
    }
    static void delete_local()
    {
        delete local_instance;
        local_instance = nullptr;
    }
};

Singleton * Singleton::local_instance = nullptr;//值得注意
mutex Singleton::my_mutex;

int main() 
{    
     Singleton * s1 = Singleton::getInstance();
     Singleton * s2 = Singleton::getInstance();
     Singleton::delete_local();
    return 0;
}

双重锁定的优点就是,只有第一次实例化单例类才需要触发锁,之后再调用这个函数就会被外层的if给屏蔽掉,大大提升了效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值