C++单例模式

单例模式

单例模式中一个类只有一个对应实例

1. 懒汉式

#include <iostream>
using namespace std;

class foo
{
public:
    static foo* GetInstance(int data1) {
        if (m_pInstance == nullptr)
            m_pInstance = new foo(data1);
        return m_pInstance;
    }
    void print() {
        cout << data1 << data2 << endl;
    }
private:
    int data1;
    int data2;
    foo(int data1) :data1(data1) {
        data2 = 10086;
    }
    foo(const foo&) = delete; // 拒绝复制构造
    foo& operator=(const foo&) = delete; // 拒绝赋值
    static foo* m_pInstance;
};
//私有静态成员必须先初始化
foo* foo::m_pInstance = nullptr; 

int main()
{
    foo *a = foo::GetInstance(2); // 要使用时才初始化
    a->print();
}

/* 问题
1. 多线程时 m_pInstance 竞争
2. 内存泄漏, 因为没有 delete */

2. 线程安全、内存安全懒汉式

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

class foo
{
public:
    static shared_ptr<foo> GetInstance(int data1) {
        if (m_pInstance == nullptr) { // 先检查避免大量锁开销
            lock_guard<mutex> lk(m_mutex); // lk 局部变量析构后解锁
            // lock_guard 为互斥锁, 当它被析构后才解锁
            if (m_pInstance == nullptr)
                m_pInstance = shared_ptr<foo>(new foo(data1));
        }
        return m_pInstance;
    }
    void print() {
        cout << data1 << data2 << endl;
    }
private:
    int data1;
    int data2;
    foo(int data1) :data1(data1) {
        data2 = 10086;
    }
    foo(const foo&) = delete; // 拒绝复制构造
    foo& operator=(const foo&) = delete; // 拒绝赋值
    static shared_ptr<foo> m_pInstance;
    static mutex m_mutex;
};
//私有静态成员必须先初始化
shared_ptr<foo> foo::m_pInstance = nullptr;
mutex foo::m_mutex;

int main()
{
    auto a = foo::GetInstance(2); // 要使用时才初始化
    a->print();
}

3. 推荐懒汉式 (Magic Static)

#include <iostream>
using namespace std;

class foo
{
public:
    /* 线程安全!
    * 用到C++11标准中的Magic Static特性
    * 如果当变量在初始化的时候,并发同时进入声明语句,
    * 并发线程将会阻塞等待初始化结束
    * */
    static foo& GetInstance(int data1) {
        static foo instance(data1);
        return instance;
    }
    void print() {
        cout << data1 << data2 << endl;
    }
private:
    int data1;
    int data2;
    foo(int data1) :data1(data1) {
        cout << "initial" << endl;
        data2 = 10086;
    }
    foo(const foo&) = delete; // 拒绝复制构造
    foo& operator=(const foo&) = delete; // 拒绝赋值
};

int main()
{
    foo& a = foo::GetInstance(2); // 要使用时才初始化
    foo& b = foo::GetInstance(2); // 只初始化一次
    a.print();
}

4. CRTP 奇异递归模板单列模式

在某些情况下,我们系统中可能有多个单例,如果都按照这种方式的话,实际上是一种重复,有没有什么方法可以只实现一次单例而能够复用其代码从而实现多个单例呢?

template<typename T>
class foo
{
public:
    static T& GetInstance(int data1) {
        static foo instance(data1);
        return instance;
    }
    virtual ~foo() {}
    void print() {
        cout << data1 << data2 << endl;
    }
protected:
    int data1;
    int data2;
    foo(int data1) :data1(data1) { //构造必须protected
        cout << "initial" << endl;
        data2 = 10086;
    }
    foo(const foo&) = delete; // 拒绝复制构造
    foo& operator=(const foo&) = delete; // 拒绝赋值
};

// 为了保证每个继承类都是单例
class derive :public foo<derive> {
    friend class foo<derive>; // 这里必须用友元使用私有构造
    // 使用 GetInstance 能继承fii
};

5. 函数模板返回引用方式单例

class A
{
public:
    A() {}
    ~A(){}
};

template<typename T>
T& get_global(){
    static T instance;
    return instance;
}

int main()
{
    // 虽然能得到全局的单例但是 A 是可以定义多个的
    A& instance_1 = get_global<A>();
    A& instance_2 = get_global<A>();
}

6. 饿汉单例模式

// 线程安全
class foo
{
public:
    static foo* GetInstance() {
        return m_pInstance;
    }
private:
    foo(){}
    foo(const foo&) = delete; // 拒绝复制构造
    foo& operator=(const foo&) = delete; // 拒绝赋值
    static foo* m_pInstance;
};
foo* foo::m_pInstance = new foo(); // 静态直接初始化
posted @ 2020-10-17 00:27  xytpai  阅读(224)  评论(0编辑  收藏  举报