单例模式 1.最简单的单例模式,不考虑线程安全以及内存泄漏 2.考虑了内存泄漏和线程安全的单例模式

#pragma once
#include <iostream>

using namespace std;

class Singleton
{
private:
    Singleton() {
        cout << "construct" << endl;
    }
    Singleton(Singleton& s) = delete; // 拷贝构造函数禁用
    Singleton& operator=(const Singleton&) = delete; // 拷贝赋值运算符禁用
    static Singleton* singleton_ptr;

public:
    ~Singleton()
    {
        if (singleton_ptr != nullptr)
            delete singleton_ptr;
        cout << "desconstruct" << endl;
    }

    static Singleton* get_instance()
    {
        if (singleton_ptr == nullptr) // (1)注意这里不是线程安全的,当两个线程同时判断时,会进行两次实例化
            singleton_ptr = new Singleton;
        return singleton_ptr;
    }

};
Singleton* Singleton::singleton_ptr = nullptr;

int main()
{
    Singleton* ptr1 = Singleton::get_instance();
    Singleton* ptr2 = Singleton::get_instance();
}

上边代码有两个问题:

  1. new了一个对象,但是却没有delete,这样会造成内存泄漏,解决方法:使用智能指针
  2. (1)处会导致线程不安全,从而创建出多个对象,解决方法:加锁

2.考虑了内存泄漏和线程安全的单例模式

#pragma once
#include <iostream>
#include <memory>
#include <mutex>

using namespace std;

class Singleton
{
private:
    Singleton() 
    {
        cout << "construct" << endl;
    }
    Singleton(Singleton& s) = delete; // 拷贝构造函数禁用
    Singleton& operator=(const Singleton&) = delete; // 拷贝赋值运算符禁用
    static shared_ptr<Singleton> singleton_ptr; // 这里指针用智能指针
    static mutex mu;

public:

    ~Singleton()
    { 
        cout << "desconstruct" << endl;
    }

    static shared_ptr<Singleton> get_instance()
    {
        if (singleton_ptr == nullptr)  // 两个if语句,双检锁。只有当指针为空的时候才上锁,毕竟锁的消耗还是挺大的
        {
            lock_guard<mutex> lck(mu); // lock_guard 在构造函数里开锁,在析构函数里解锁
            if (singleton_ptr == nullptr) // 注意这里不是线程安全的,当两个线程同时判断时,会进行两次实例化
                singleton_ptr = shared_ptr<Singleton>(new Singleton);
        }
        return singleton_ptr;
    }
};

shared_ptr<Singleton> Singleton::singleton_ptr = nullptr;
mutex Singleton::mu;

int main()
{
    shared_ptr<Singleton> ptr1 = Singleton::get_instance();
    shared_ptr<Singleton> ptr2 = Singleton::get_instance();

    return 0;
}