单例模式的实现--C++
实现单例模式
只能生成一个实例的类是实现了单例模式的类型
//(1)只适合单线程环境的的单例模式实现
class Singleton
{
private:
    Singleton();
    ~Singleton();
    Singleton(const Singleton&);
    Singleton& operator=(const Singleton&);
private:
    static Singleton* instance;
public:
    static Singleton* Instance()
    {
        if (instance == nullptr)          //这个地方多线程是时候有可能出现错误。
        {
            instance = new Singleton();
        }
        return instance;
    };
};
Singleton* Singleton::instance = nullptr;
//以上的范例只适合在单线程下操作,如果在多线程中多个线程同时运行到判断instance
//是否为nullptr的if语句,并且instance的确没有创建时,那么多个线程都会创建一个
//一个实例,此时类型Singleton就不再满足单例模式的需求了。且此类型Singleton的写法
//会存在内存泄露的问题。
//针对内存泄露的问题,我们有以下两种解决方法。
//(1.1)解决内存泄露的第一种方式:智能指针解决内存泄露问题
#include<memory>
using namespace std;
class Singleton
{
private:
    Singleton();
    ~Singleton();
    Singleton(const Singleton&);
    Singleton& operator=(const Singleton&);
private:
    static shared_ptr<Singleton> instance;
public:
    static shared_ptr<Singleton> Instance()
    {
        if (instance == nullptr)          //这个地方多线程是时候有可能出现错误。
        {
            instance = make_shared<Singleton>();
        }
        return instance;
    };
};
shared_ptr<Singleton> Singleton::instance = nullptr;
//将instance定义为智能指针的形式,则不会出现内存泄露的问题。
//(1.2) 解决内存泄露的第二种方式,利用类中类和静态成员结合的方式
class Singleton
{
private:
    Singleton();
    ~Singleton();
    Singleton(const Singleton&);
    Singleton& operator=(const Singleton&);
private:
    static Singleton* instance;
private:
    class Deletor
    {
    public:
        ~Deletor()
        {
            if (Singleton::instance != nullptr)
            {
                delete Singleton::instance;
                Singleton::instance = nullptr;
            }
        }
    };
    static Deletor deletor;
public:
    static Singleton* Instance()
    {
        if (instance == nullptr)          //这个地方多线程是时候有可能出现错误。
        {
            instance = new Singleton();
        }
        return instance;
    };
};
Singleton* Singleton::instance = nullptr;
//这样在程序运行结束的时候,会调用deletor的析构函数,
//该函数会删除单例的唯一的实例。
#include<mutex>
using namespace std;
class Singleton
{
private:
    Singleton();
    ~Singleton();
    Singleton(const Singleton&);
    Singleton& operator=(const Singleton&);
private:
    static Singleton* instance;
    static mutex my_mutex;
private:
    class Deletor
    {
    public:
        ~Deletor()
        {
            if (Singleton::instance != nullptr)
            {
                delete Singleton::instance;
                Singleton::instance = nullptr;
            }
        }
    };
    static Deletor deletor;
public:
    static Singleton* Instance()
    {
        my_mutex.lock(); //对这一部分的代码进行加锁,以免创建多个对象
        if (instance == nullptr)
        {
            instance = new Singleton();
        }
        my_mutex.unlock();
        return instance;
    };
};
Singleton* Singleton::instance = nullptr;
mutex Singleton::my_mutex;
//以上的方式可用于多线程的程序中,但是效率不是太高,因为
//在第一次创建了一个实例之后,之后每次使用接口,都需要再加锁。
//可以修改成以下的双判断加锁方式
#include<mutex>
using namespace std;
class Singleton
{
private:
    Singleton();
    ~Singleton();
    Singleton(const Singleton&);
    Singleton& operator=(const Singleton&);
private:
    static Singleton* instance;
    static mutex my_mutex;
private:
    class Deletor
    {
    public:
        ~Deletor()
        {
            if (Singleton::instance != nullptr)
            {
                delete Singleton::instance;
                Singleton::instance = nullptr;
            }
        }
    };
    static Deletor deletor;
public:
    static Singleton* Instance()
    {
        if (instance == nullptr)
        {
            my_mutex.lock(); //对这一部分的代码进行双判断加锁,提高性能。
            //除了第一次使用接口,其他使用接口时再也不会进行加锁。
            if (instance == nullptr)
            {
                instance = new Singleton();
            }
            my_mutex.unlock();
        }
        return instance;
    };
};
Singleton* Singleton::instance = nullptr;
mutex Singleton::my_mutex;
//but,以上的代码仍然可能会存在问题。
//在某些内存模型中(虽然不常见)或者是由于编译器的优化以及运行时优化等等原因,
//使得instance虽然已经不是nullptr但是其所指对象还没有完成构造,
//这种情况下,另一个线程如果调用getInstance()就有可能使用到一个不完全初始化的对象。
//因为C++11规定了local static在多线程条件下的初始化行为,要求编译器保证内部静态变量的线程安全性。
//所以我们将代码修改成以下:
#include<mutex>
using namespace std;
class Singleton
{
private:
    Singleton();
    ~Singleton();
    Singleton(const Singleton&);
    Singleton& operator=(const Singleton&);
public:
    static Singleton& Instance()
    {
        static Singleton instance;
        return instance;
    };
};
posted on 2021-10-07 09:53 xcxfury001 阅读(41) 评论(0) 收藏 举报
 
                     
                    
                 
                    
                 
                
            
         
 
         浙公网安备 33010602011771号
浙公网安备 33010602011771号