zoukankan      html  css  js  c++  java
  • C++对单例模式实现的总结

    目录

    1、饿汉模式(一开始就初始化单例对象)

    2、懒汉模式(需要的时候在实例化单例对象)

    3、C++11简化版(必看精髓)

    4、单例模板

    1、饿汉模式(一开始就初始化单例对象)

    优点:不用担心多线程问题。

    缺点:可能在整个程序中就没有用到这个单例对象,造成浪费。

    实现:

    class Singleton
    {
    public:
        static Singleton* GetInstance()//公有static方法,用于获取单例句柄
        {
            return &singleton_;
        }
    private:
        Singleton();//构造函数私有
        static Singleton singleton_ ;//私有static单例对象
    };
     
     
    Singleton Singleton::singleton_;
    int main()
    {
        auto p1 = Singleton::GetInstance();
        auto p2 = Singleton::GetInstance();
        bool result=( p1 == p2);//判断是否指向同一个单例对象
        std::cout <<  result << std::endl;
     
        return 0;
    }

    2、懒汉模式(需要的时候在实例化单例对象)

    优点:不会像饿汉模式一样造成资源浪费。只是需要考虑多线程安全,实现上稍稍复杂一点。

    class Singleton
    {
    public:
        static Singleton* GetInstance()
        {
            if (p_singleton_ == nullptr)//第一次检查:实例化单例对象后,就不会再进入加锁逻辑
            {
                std::lock_guard<std::mutex> lock(mux_);
                if (p_singleton_ == nullptr)//第二次检查:可能两个线程同时通过第一次检查,一个线程获得锁时,可能另外一个线程已经实例化单体
                {
                    p_singleton_ = new Singleton();
                }
            }
            return p_singleton_;
        }
    private:
        Singleton();
        static Singleton * p_singleton_ ;
        static std::mutex mux_;
    };
     
    std::mutex Singleton::mux_;
    Singleton * Singleton::p_singleton_ = nullptr;
    int main()
    {
        auto p1 = Singleton::GetInstance();
        auto p2 = Singleton::GetInstance();
        bool result=( p1 == p2);
        std::cout <<  result << std::endl;
     
        return 0;
    }

    其实记住懒汉模式就确保万无一失了,因为当在程序一开始时就调用懒汉模式的GetInstance,就实例化出单例,这等价于饿汉模式。

    3、C++11简化版(必看精髓)

    但是看起来懒汉模式比较复杂,我们还可以利用C++11对static的改进性质简化代码。

    class Singleton
    {
    public:
        static Singleton* GetInstance()
        {
            static Singleton  singleton;//此变量存在静态区,C++11自带两段检查锁机制来确保static变量实例化一次
            return &singleton;
        }
    private:
        Singleton();
    };
     
    int main()
    {
        auto p1 = Singleton::GetInstance();
        auto p2 = Singleton::GetInstance();
        bool result=( p1 == p2);
        std::cout <<  result << std::endl;
     
        return 0;
    }

    这种单例模式的写法可谓是简单地不能再简单了。为什么正确呢?

    其实static变量本身全局就只有一份,与单例对象的性质极其相似。而C++11为了确保只初始化static变量一次,提供了两段检查锁机制(在上述代码的汇编代码中,可以清楚地看到两段检查锁的逻辑)。换言之,C++11对于static变量,自带使用了单例模式,自然不用我们再费事。

    4、单例模板

    在上述代码的基础上改成模板的形式:

    #include <iostream>
    #include <mutex>
    using namespace std;
     
    class A {
     
    };
     
    class B {
     
    };
     
    template <typename T>
    class Singleton2 {
    public:
        static T * GetInstance() {
            static T t;
            return &t;
        }
    protected:
        Singleton2() {}
    };
     
    template <typename T>
    class Singleton {
    public:
        static T * GetInstance() {
            if (pSingle == nullptr) {
                lock_guard<mutex> lock(mtx);
                if (pSingle == nullptr) {
                    pSingle = new T();
                }
            }
            return pSingle;
        }
    private:
        Singleton() {}
        static T * pSingle;
        static mutex mtx;
    };
     
     
    //mutex Singleton<A>::mtx;
    //mutex Singleton<B>::mtx;
    //
    //A* Singleton<A>::pSingle = nullptr;
    //B* Singleton<B>::pSingle = nullptr;
    //注释部分代码可以执行,只是每个类都需要单独的两行定义,
    //所以使用下面的方法更便捷。
    template <typename T>
    mutex Singleton<T>::mtx;
     
    template <typename T>
    T* Singleton<T>::pSingle = nullptr;
     
    int main() {
     
        auto pA = Singleton<A>::GetInstance();
        auto pB = Singleton<B>::GetInstance();
     
        auto pA2 = Singleton<A>::GetInstance();
        auto pB2 = Singleton<B>::GetInstance();
     
        cout << pA << endl;
        cout << pB << endl;
        cout << pA2 << endl;
        cout << pB2 << endl;
     
        return 0;
    }

    但是上述代码有一个问题,类A和B可以直接构造,和单例的语义不太符合。为此,将A和B类的构造函数设定为private,并声明Singleton<T>为相应的友元函数

    #include <iostream>
    #include <mutex>
    using namespace std;
     
    template <typename T>
    class Singleton2 {
    public:
        static T * GetInstance() {
            static T t;
            return &t;
        }
    protected:
        Singleton2() {}
    };
     
    template <typename T>
    class Singleton {
    public:
        static T * GetInstance() {
            if (pSingle == nullptr) {
                lock_guard<mutex> lock(mtx);
                if (pSingle == nullptr) {
                    pSingle = new T();
                }
            }
            return pSingle;
        }
    private:
        Singleton() {}
        static T * pSingle;
        static mutex mtx;
    };
     
    template <typename T>
    mutex Singleton<T>::mtx;
    template <typename T>
    T* Singleton<T>::pSingle = nullptr;
     
    class A {
        friend Singleton<A>;
    private:
        A() {}
    };
     
    class B {
        friend Singleton<B>;
    private:
        B() {}
    };
     
     
    int main() {
     
        auto pA = Singleton<A>::GetInstance();
        auto pB = Singleton<B>::GetInstance();
     
        auto pA2 = Singleton<A>::GetInstance();
        auto pB2 = Singleton<B>::GetInstance();
     
        cout << pA << endl;
        cout << pB << endl;
        cout << pA2 << endl;
        cout << pB2 << endl;
     
        return 0;
    }

    文章是转载自csdn

    https://blog.csdn.net/songchuwang1868/article/details/87882778

  • 相关阅读:
    五、Java对象和类
    四、JavaString字符串
    三、Java语句
    二、Java基本数据类型
    一、Java主类结构
    bat常用命令
    iOS 如何获得app的版本和系统的版本
    英语----时态---将来时态的四种对比
    英语----时态---将来时态的
    英语----时态---现在进行时与过去进行时
  • 原文地址:https://www.cnblogs.com/Fightingbirds/p/13806856.html
Copyright © 2011-2022 走看看