zoukankan      html  css  js  c++  java
  • 单例模式(Singleton Pattern)

    单例模式设计到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一对象的方式,可以直接访问,不需要实例化该类的对象。

     注意:

    单例类只能有一个实例。

    单例类必须自己创建自己的唯一实例。

    单例类必须给所有其他对象提供这一实例。

    意图:保证一个类仅有一个实例,并提供一个访问他的全局访问点。

    主要解决:一个全局使用的类频繁地创建于销毁。

    何时使用:控制实例数目,节省系统资源的时候。

    如何解决:判断系统时候已经有这个单例,如果有则返回,如果没有则创建。

    关键代码:构造函数是私有的。

    实例:1、一个班级只有一个班主任。

               2、一些设备管理器设计为单例模式,

    优点:1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例

               2、避免对资源的多重占用。

    缺点:没有接口,不能继承,与单一职责原则冲突。

    使用场景:1、要求生产唯一序列号。

                      2、创建的一个对象需要消耗的资源过多,比如I/O与数据库的连接等。

    C++代码实现:

    1、懒汉式是使用到时才实例化对象,在调用到getInstance()方法时才会new出一个单例对象。

    可能会带来的问题:

    #include<iostream>
    #include<memory>
    #include<mutex>
    using namespace std;
    
    //创建懒汉单例类
    class SingleObject {
    public:
        typedef shared_ptr<SingleObject> ptr;
        ~SingleObject()
        {
            cout << "析构函数~!~!" << endl;
        }
        //C++11 关键字delete 表民绝对禁止使用拷贝构造函数
        SingleObject(SingleObject&) = delete;
        SingleObject& operator=(const SingleObject&) = delete;
    
        static SingleObject* getInstance()
        {
            if (instance == nullptr)
            {
                instance = new SingleObject;
            }
            return instance;
        }
    
    private:
        SingleObject()
        {
            cout << "构造函数~!~!" << endl;
        }
        static SingleObject* instance;
    };
    //类的数据成员不能在类的声明体中初始化
    //必须在类外进行初始化
    SingleObject* SingleObject::instance = nullptr;
    
    int main()
    {
        SingleObject* ins = SingleObject::getInstance();
        SingleObject* ins_2 = SingleObject::getInstance();
        //SingleObject* ins_3 = new SingleObject;    //编译无法通过
        
        system("pause");
        return 0;
    }

    1、线程安全问题:在多线程环境下,假设存在两个线程同时调用到getInstance()方法。第一个线程判断isnstance==nullptr,于是实例化单例;此时第二个线程判断isnstance==nullptr,于是也开始实例化单例。这样就不能保证单例的唯一性。

    解决办法:加锁。

    2、内存泄漏:类中只负责new出对象,却没有负责delete对象。析构函数中却没有被调用,所以会导致内存泄漏。

    解决办法:使用共享指针(shared_ptr)。

      为什么不在析构函数中调用delete?自己在思考:static成员函数中new出的对象可以在析构函数中delete吗?

                                            

    2、线程安全、内存安全的懒汉单例模式

    #include<iostream>
    #include<memory>
    #include<mutex>
    using namespace std;
    //创建线程安全、内存安全的懒汉类
    class SingleObject {
    public:
        //为shared_ptr定义一个别名Ptr
        typedef shared_ptr<SingleObject> Ptr;
    
        ~SingleObject()
        {
            cout << "析构函数~!~!" << endl;
        }
        //C++11 关键字delete 表民绝对禁止使用拷贝构造函数
        SingleObject(SingleObject&) = delete;
        SingleObject& operator=(const SingleObject&) = delete;
        static Ptr getInstance()
        {
            if (instance == nullptr)
            {
                //互斥锁
                lock_guard<mutex> lk(m_mutex);
                if (instance == nullptr)
                {
                    instance = shared_ptr<SingleObject>(new SingleObject);
                    //instance = Ptr(new SingleObject); 和上面相同
                }
            }
            return instance;
        }
    
    private:
        SingleObject()
        {
            cout << "构造函数~!~!" << endl;
        }
        static Ptr instance;
        static mutex m_mutex;
    };
    //类的数据成员不能在类的声明体中初始化
    //必须在类外进行初始化
    SingleObject::Ptr SingleObject::instance = nullptr;
    mutex SingleObject::m_mutex;
    
    
    int main()
    {
        SingleObject::Ptr ins = SingleObject::getInstance();
        SingleObject::Ptr ins_2 = SingleObject::getInstance();
        system("pause");
        return 0;
    }

     3、懒汉单例--局部静态变量

    #include<iostream>
    using namespace std;
    
    class SingleObject {
    public:
        ~SingleObject()
        {
            cout << "析构函数~!~!" << endl;
        }
    
        //C++11 关键字delete 表民绝对禁止使用拷贝构造函数
        SingleObject(SingleObject&) = delete;
        SingleObject& operator=(const SingleObject&) = delete;
    
        static SingleObject& getInstance()
        {
            static SingleObject instance;
            return instance;
        }
    
    private:
        SingleObject()
        {
            cout << "构造函数~!~!" << endl;
        }
    };
    //类的数据成员不能在类的声明体中初始化
    //必须在类外进行初始化
    
    int main()
    {
        SingleObject& ins = SingleObject::getInstance();
        system("pause");
        return 0;
    }

    参考:https://www.cnblogs.com/sunchaothu/p/10389842.html

               https://www.cnblogs.com/sunchaothu/p/10389842.html

  • 相关阅读:
    博客推荐
    2018
    2018
    学习推荐-Postgresql学习手册
    学习推荐-Redis学习手册
    odoo开发笔记 -- odoo源码解析
    前沿技术相关
    odoo开发笔记-tree列表视图拖拽排序
    odoo开发笔记-日期时间相关操作
    odoo开发笔记 -- 官方模块一览表
  • 原文地址:https://www.cnblogs.com/dreammmz/p/13512017.html
Copyright © 2011-2022 走看看