单例模式的实现--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)    收藏  举报

导航