C++ 设计模式-单例模式

设计模式介绍

一、单例模式介绍

1. 单例模式定义

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

2. 单例模式的本质

控制实例的数目

3. 单例模式的结构和说明

(1) 结构

单例模式的结构
Singleton:负责创建 Singleton类自己的唯一实例,并提供一个 getinstance I的方法,让外部来访问这个类的唯一实例。

(2) 调用顺序
懒汉式

懒汉式调用顺序

饿汉式

饿汉式调用顺序

4. 单例模式适用情况

当需要控制一个类的实例只能有一个,而且客户只能从一个全局访问点访问它时,可以选用单例模式,这些功能恰好是单例模式要解决的问题。

5. 单例模式优缺点

  • 时间和空间
    懒汉式典型的时间换空间, 饿汉式典型的空间换时间

懒汉式是典型的时间换空间,也就是每次获取实例都会进行判断,看是否需要创建实例,浪费判断的时间。当然,如果一直没有人使用的话,那就不会创建实例,则节约内存空间。
饿汉式是典型的空间换时间,当类装载的时候就会创建类实例,不管你用不用,先创建出来,然后每次调用的时候,就不需要再判断了,节省了运行时间。

  • 线程安全
    不加同步的懒汉式是线程不安全的, 饿汉式是线程安全的

当然懒汉式也是可以实现线程安全的, 可以采取双重加锁检查的方法

6. 相关模式

很多模式都可以使用单例模式,只要这些模式中的某个类,需要控制实例为一个的时候,就可以很自然地使用上单例模式。比如抽象工厂方法中的具体工厂类就通常是个单例

二、单例模式示例代码

这里只介绍比较常见的经典方式,其他奇淫巧技不做介绍

1. 懒汉式

#include <iostream>
#include <string>
#include <memory>
#include <mutex>

using namespace std;

template <typename T>
class Singleton{
public:
    template <typename... Args>
    static T* Instance(Args&&... args){
        if(m_instance == nullptr){
            std::unique_lock<std::mutex> lock(mutex);
            if(m_instance == nullptr){
                m_instance = new T(std::forward<Args>(args)...);
            }
        }
        return m_instance;
    }

    Singleton() = delete;
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
    Singleton(Singleton&&) = delete;
    Singleton& operator=(Singleton&&) = delete;
private:
    static T* m_instance;
    std::mutex;
};
template <typename T> T* Singleton<T>::m_instance = nullptr;


//test
struct A
{
    A(const string&){cout<<"lvaue"<<endl;}
    A(string&& x){cout<<"rvaue"<<endl;}
};
struct B
{
    B(const string&){cout<<"lvaue"<<endl;}
    B(string&& x){cout<<"rvaue"<<endl;}
};
struct C
{
    C(int x, double y){}
    void Fun(){cout<<"test"<<endl;}
};

int main(){
    string str = "bb";

    //创建A类型的单例
    Singleton<A>::Instance(str);

    //创建B类型的单例,临时变量str被move之后变成右值,然后可以根据移动语义来避免复制
    Singleton<B>::Instance(std::move(str));

    // 创建C类型的单例,含两个参数
    Singleton<C>::Instance(1, 3.14)->Fun();
    return 0;
}

2. 饿汉式

#include <iostream>
#include <string>
#include <memory>

using namespace std;

template <typename T>
class Singleton{
public:
    static T* Instance(){
        return &m_instance;
    }

    Singleton() = delete;
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
    Singleton(Singleton&&) = delete;
    Singleton& operator=(Singleton&&) = delete;
private:
    static T m_instance;
};
template <typename T> T Singleton<T>::m_instance;

struct A
{
    A() = default;
    void Fun(){std::cout<<"A::Fun"<<std::endl;};
};
struct B
{
    B() = default;
    void Fun(){std::cout<<"B::Fun"<<std::endl;};
};

int main(){
    Singleton<A>::Instance()->Fun();
    Singleton<B>::Instance()->Fun();

    return 0;
}

3. 静态局部变量式

#include <iostream>
#include <string>
#include <memory>

using namespace std;

template <typename T>
class Singleton{
public:
    template <typename... Args>
    static inline T& GetInstance(Args&&... args){
        static T obj {std::forward<Args>(args)...};
        return obj;
    }

    template <typename ... Args>
    static inline T* GetInstancePtr(Args... args){
        return &GetInstance(args...);
    }

    Singleton() = delete;
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
    Singleton(Singleton&&) = delete;
    Singleton& operator=(Singleton&&) = delete;
};

//test
struct A
{
    A(const string&){cout<<"lvaue"<<endl;}
    A(string&& x){cout<<"rvaue"<<endl;}
};
struct B
{
    B(const string&){cout<<"lvaue"<<endl;}
    B(string&& x){cout<<"rvaue"<<endl;}
};
struct C
{
    C(int x, double y){}
    void Fun(){cout<<"test"<<endl;}
};

int main(){
    string str = "bb";

    //创建A类型的单例
    Singleton<A>::GetInstance(str);

    //创建B类型的单例,临时变量str被move之后变成右值,然后可以根据移动语义来避免复制
    Singleton<B>::GetInstance(std::move(str));

    // 创建C类型的单例,含两个参数
    auto ptr = Singleton<C>::GetInstancePtr(1, 3.14);
    // 获取单例并调用单例对象的方法
    ptr->Fun();

    return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值