C++ 单例模式设计

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jinsenianhua2012/article/details/82634179

C++ 单例模式设计

c++中,类对象被创建时,编译系统为对象分配内存空间,并自动调用构造函数,由构造函数完成成员的初始化工作,也就是说使用构造函数来初始化对象。

  1. 那么我们需要把构造函数设置为私有的 private,这样可以禁止别人使用构造函数创建其他的实例。

  2. 又单例类要一直向系统提供这个实例,那么,需要声明它为静态的实例成员,在需要的时候,才创建该实例。

  3. 且应该把这个静态成员设置为 null,在一个public 的方法里去判断,只有在静态实例成员为 null,也就是没有被初始化的时候,才去初始化它,且只被初始化一次。

    • 但是如果使用全局或者静态变量方式,会影响其封装性,很难保证代码不会对全局变量做出修改或影响,一个好的办法是:让类自身负责保存其唯一实例
// 下面是一种单例示例
class Singleton {
public :
    static Singleton* getInstance()
    {
        if(_instance == NULL)
        {
            _instance = new Singleton();
        }
        return _instance;
    }

private :
    // 设置为私有构造函数,防止外部调用实例化
    Singleton()
    {
        cout <<"Instance"<<endl;
    }

    static Singleton* _instance;
};

Singleton * Singleton::_instance = NULL;
  • 上述单例在单线程情况下没有问题,但是在多线程中就会出问题。比如两个线程同时请求并创建实例,便出问题了
    为单例添加线程同步功能
    // 考虑多线程下的单例情况, 互斥信号量解决方案
    class Singleton{
    public:
        // get 方法
        static Singleton* getSingleton()
        {
            // 通过互斥信号机制,为代码枷锁
            lock();
            // 判断是否为 NULL
            if(NULL == instance)
            {
                instance = new Singleton();
            }

            // 使用完毕解锁
            unlock();

            return instance;
        }
    private:
        Singleton(){

        }

        static Singleton* instance;
    };
    Singleton* Singleton::instance = NULL:
  • 上面的方案缺点:每次get调用时都会同步加锁,如果线程比较多时,就会有大量的线程阻塞,且加锁也是个耗时的操作,所以除非有必要尽量避免加锁操作
    // 采用双重判断的线程安全方式实现单例
    class Singleton{
    public :
        // get方法
        static Singleton* getInstance(){
            // 先判断是否NULL,只有NULL时才需要加锁
            if(NULL == instance)
            {
                lock();
                // 再次判断是否NUKK (注意,这里需要再次判断)
                if(NULL == instance)
                {
                    instance = new Singleton();
                }
                unlock();   // 解锁

            }
            return instance;
        }
    private:
        static Singleton* instance;
        Singleton()
        {
            // 私有构造函数
        }
    };
    Singleton* Singleton::instance = NULL;
  • 饿汉式单例实现方式,在静态区先初始化 instance
    class Singleton{
    public:
        //get 方法
        static Singleton* getInstance()
        {
            return instance;
        }
    private:
        Singleton(){}
        static Singleton* instance; 
    };

    // 直接初始化
    Singleton* Singleton::instance = new Singleton();

注意:静态初始化实例可以保证线程安全,因为静态实例初始化在程序开始时进入主函数之前,就由主线程以单线程方式完成了初始化!饿汉式的单例类,也就是静态初始化实例保证其线程安全性,故在性能需求较高时,应使用这种模式,避免频繁的锁争夺。

  • 注意!! 上面的单例模式没有 destory() 方法,也就是说,貌似上面的单例类没有主动析构这个唯一实例!然而这就导致了一个问题,在程序结束之后,该单例对象没有delete,导致内存泄露!下面是一些大神的方法:一个妥善的方法是让这个类自己知道在合适的时候把自己删除,或者说把删除自己的操作挂在操作系统中的某个合适的点上,使其在恰当的时候被自动执行。
  • 我们知道,程序在结束的时候,系统会自动析构所有的全局变量。事实上,系统也会析构所有的类的静态成员变量。利用这些特征,我们可以在单例类中定义一个这样的静态成员变量,而它的唯一工作就是在析构函数中删除单例类的实例。如下面的代码中的Garbage类:
    class Singleton{
    public :
        // get 方法
        static Singleton* getInstance()
        {
            if(NULL == instance)
            {
                instance = new Singleton();
            }
            return instance;
        }

        //c++ 嵌套的内部类,作用是删除单例类对象,Garbage被定义为Singleton的内嵌类,以防该类被在其他地方滥用。
        class Garbage{
        public :
            ~Garbage(){
                if(Singleton::instance != NULL)
                {
                    delete Singleton::instance;
                }
            }
        };

    private :
        //单例类中声明一个触发垃圾回收类的静态成员变量,它的唯一工作就是在析构函数中删除单例类的实例,利用程序在结束时析构全局变量的特性,选择最终的释放时机;
        static Garbage garbage;

        // 声明静态实例
        static Singleton* instance;

        Singleton(){}
    };

    //初始化内部的静态变量,目睹是启动删除的析构函数,如果不初始化,就不会被析构
    //内部类可以访问外部类的私有成员,外部类不能访问内部类的私有成员!
    Singleton::Garbage Singleton::garbage;

    Singleton* Singleton::instance = NULL;
  • 总结单例模式的特征:

    1. 只有一个类实例:
      将构造函数私有化

    2. 提供一个全局访问点:
      类中创建静态成员和静态成员方法

    3. 禁止拷贝:
      把拷贝函数声明私有化,并且不提供实现;将赋值运算符私有化,防止对象被赋值

    // 比较完整的 C++ 单例设计
    class Singleton{
    public :
        // get 方法
        static Singleton* getSingleton()
        {
            if(NULL == instance)
            {
                lock();
                if(NULL == instance)
                {
                    instance = new Singleton();
                }
                unlock();
            }
            return instance;
        }
        // c++ 嵌套的内部类,实现单例的删除操作
        class Garbage{
            public :
                ~Garbage()
                {
                    if(Singleton::instance != NULL)
                    {
                        delete Singleton::instance;
                    }
                }
        };

    private :

        static Garbage garbage;//定义静态成员变量,利用程序在结束时会起购全局变量的特向释放单例

        static Singleton *instance;

        Singleton(){...}
        ~Singleton(){...}

        Singleton(const Singleton &copy);//私有化拷贝函数
        Singleton & operate=(const Singleton &other);   // 私有化赋值运算符

    };

    Singleton::Garbage Singleton::garbage;
    Singleton* Singleton::instance = NULL;

猜你喜欢

转载自blog.csdn.net/jinsenianhua2012/article/details/82634179
今日推荐