• C++【特殊类的设计】【单例设计模式】


    特殊类的设计

    1.不能被拷贝的类

    在我们上一章的unique中就是让我们的对象不能被拷贝。
    我们这里可以将赋值和拷贝构造都设置为私有属性。

    class CopyBan
    {
    // ...
    private:
    	Copy(const Copy&);
    	Copy& operator=(const Copy&);
    //...
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2.只能在堆上创建对象的类

    #include 
    class HeapOnly
    {
        //将析构函数私有
    private:
        ~HeapOnly()
        {}
    private:
        int _a;
    };
    int main() {
        HeapOnly hp1;
        static HeapOnly hp2;
        HeapOnly* ptr =new HeapOnly;
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    正常定义的对象我们都需要调用析构函数,如果我们把析构函数设置成私有,那么我们的上面代码中的hp1,hp2都会报错,而我们的ptr因为没有调用析构函数,所以可以正常编译通过。
    那么我们就需要手动释放ptr,也就是写成下面的写法

    #include 
    using namespace std;
    class HeapOnly
    {
    public:
        static void Delete(HeapOnly* p)
        {
            delete p;
        }
        //将析构函数私有
    private:
        ~HeapOnly()
        {
            cout<<"heapOnly"<<endl;
        }
    private:
        int _a;
    };
    int main() {
    //    HeapOnly hp1;
    //    static HeapOnly hp2;
        HeapOnly* ptr =new HeapOnly;
        ptr->Delete(ptr);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    或者将构造函数私有化,采用下面的写法

    #include 
    using namespace std;
    class HeapOnly
    {
    public:
        //提供一个共有的,获取对象的方式,对象控制是new出来的
        static HeapOnly* CreateObject()
        {
            return new HeapOnly;
        }
    private:
        HeapOnly()
            :_a(0)
        {}
    private:
        int _a;
    };
    int main() {
    //    HeapOnly hp1;
    //    static HeapOnly hp2;
        HeapOnly* hp3 =HeapOnly::CreateObject();
        delete hp3;
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    但是我们还需要防止别人采用拷贝构造的方式在栈上开辟空间,这里我们还需要将拷贝构造和赋值设置成私有的。

    #include 
    using namespace std;
    class HeapOnly
    {
    public:
        //提供一个共有的,获取对象的方式,对象控制是new出来的
        static HeapOnly* CreateObject()
        {
            return new HeapOnly;
        }
    private:
        HeapOnly(const HeapOnly& hp)=delete;
        HeapOnly& operator=(const HeapOnly& hp)=delete;
        HeapOnly()
            :_a(0)
        {}
    private:
        int _a;
    };
    int main() {
    //    HeapOnly hp1;
    //    static HeapOnly hp2;
        HeapOnly* hp3 =HeapOnly::CreateObject();
        //拷贝构造的空间在栈上
        HeapOnly copy(*hp3);
        delete hp3;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    3.只能在栈上创建的类

    #include 
    using namespace std;
    class StackOnly
    {
    public:
        static StackOnly CreateObj()
        {
            StackOnly st;
            return st;
        }
    //    StackOnly(const StackOnly& hp)=delete;
    //    StackOnly& operator=(const StackOnly& hp)=delete;
        void* operator new(size_t n)=delete;
    private:
        StackOnly()
                :_a(0)
        {}
    private:
        int _a;
    };
    int main() {
    //    StackOnly hp1;
    //    static StackOnly hp2;
        StackOnly hp3 =StackOnly::CreateObj();
    
        //拷贝构造
        //因为我们这里一定要传值返回,然后如果把传值返回给禁用了,我们这里上面的
        //正产的hp3也没有办法创建了。
        //所以这里的copy(hp3)没有办法禁用
        StackOnly copy2(hp3); //不好处理,小缺陷
    //    StackOnly * copy3=new StackOnly(hp3);
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    单例模式

    设计模式
    设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。

    使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。

    单例模式
    一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息,这种方式简化了在复杂环境下的配置管理。

    JAVA版本的单例模式

    1.饿汉模式

    饿汉模式–一开始(main函数之前)就创建出对象
    可以使用下面这种生成一个静态的对象

    //饿汉模式
    class MemoryPool
    {
    public:
    
    private:
        //构造函数私有化
        MemoryPool()
        {}
        char* _ptr= nullptr;
    
        //创建一个静态的自己的对象
        //因为静态的对象是存在静态区的,是属于所有类的
        static MemoryPool _inst;//声明
    };
    //定义,在类外进行构造
    MemoryPool MemoryPool::_inst;
    
    int main()
    {
    //    MemoryPool pool1;
        //MemoryPool pool2;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    或者像下面这样采用指针的形式

    #include 
    using namespace std;
    //饿汉模式
    class MemoryPool
    {
    public:
        static MemoryPool*GetInstance()
        {
            return _pinst;
        }
    
        void* Alloc(size_t n)
        {
            void* ptr= nullptr;
            return  ptr;
        }
    
        void Dealloc(void*ptr)
        {}
    private:
        //构造函数私有化
        MemoryPool()
        {}
        char* _ptr= nullptr;
    
        //创建一个静态的自己的对象
        //因为静态的对象是存在静态区的,是属于所有类的
        static MemoryPool* _pinst;//声明
    };
    //定义,在类外进行构造
    MemoryPool* MemoryPool::_pinst=new MemoryPool;
    
    int main()
    {
    //    MemoryPool pool1;
        //MemoryPool pool2;
        void* ptr1=MemoryPool::GetInstance()->Alloc(10);
        MemoryPool::GetInstance()->Dealloc(ptr1);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    饿汉模式:
    优点:简单,没有线程安全问题(因为它在main函数之前就执行了,不存在竞争的问题)。
    缺点:1、一个程序中,有多个单例,并且有先后创建初始化顺序要求时,饿汉无法控制
    (比方说A先创建,然后B在创建,这样是没有办法做到的,因为它们都是静态成员,我们是没有办法确定的。同一个文件中可能谁在前,谁先初始化,但是如果是在多个文件中就不好控制了)
    2、饿汉单例模式,初始化任务多的时候,会影响程序的启动速度。因为我们上面的单例的初始化是在main函数之前就创建的。

    2.懒汉模式

    懒汉模式:第一次使用对象再创建实例对象。

    #include 
    using namespace std;
    //饿汉模式
    class MemoryPool
    {
    public:
        static MemoryPool*GetInstance()
        {
            if(_pinst== nullptr)
            {
                _pinst=new MemoryPool;
            }
            return _pinst;
        }
    
        void* Alloc(size_t n)
        {
            void* ptr= nullptr;
            return  ptr;
        }
    
        void Dealloc(void*ptr)
        {}
    private:
        //构造函数私有化
        MemoryPool()
        {}
        char* _ptr= nullptr;
    
        //创建一个静态的自己的对象
        //因为静态的对象是存在静态区的,是属于所有类的
        static MemoryPool* _pinst;//声明
    };
    //定义,在类外进行构造
    MemoryPool* MemoryPool::_pinst=nullptr;
    
    int main()
    {
    //    MemoryPool pool1;
        //MemoryPool pool2;
        void* ptr1=MemoryPool::GetInstance()->Alloc(10);
        MemoryPool::GetInstance()->Dealloc(ptr1);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    优点
    1、控制顺序
    2、不影响启动速度
    缺点:
    1、相对复杂(线程安全问题)
    2、线程安全问题要处理好

    3.单例对象的释放问题

    1、一般情况下,单例对象不需要释放。一般整个程序运行期间都可能会用到。
    2、单例对象在进程正常结束之后也会资源释放
    3、有些特殊的场景需要释放,比如单例对象析构时,要进行一些持久化(往文件,数据库写)操作。

    我们可以通过定义一个内嵌类型的垃圾回收器来释放我们的空间

    #include 
    using namespace std;
    //饿汉模式
    class MemoryPool
    {
    public:
        static MemoryPool*GetInstance()
        {
            if(_pinst== nullptr)
            {
                _pinst=new MemoryPool;
            }
            return _pinst;
        }
    
        void* Alloc(size_t n)
        {
            void* ptr= nullptr;
            return  ptr;
        }
    
        void Dealloc(void*ptr)
        {}
    
        // 实现一个内嵌垃圾回收类
        class CGarbo {
        public:
            ~CGarbo()
            {
                if (_pinst)
                    delete _pinst;
            }
        };
    private:
        //构造函数私有化
        MemoryPool()
        {}
        char* _ptr= nullptr;
    
        //创建一个静态的自己的对象
        //因为静态的对象是存在静态区的,是属于所有类的
        static MemoryPool* _pinst;//声明
    };
    //定义,在类外进行构造
    MemoryPool* MemoryPool::_pinst=nullptr;
    //定义一个静态的全局的回收对象
    //在main函数结束之后,它会调用析构函数,就会释放单例对象。
    static MemoryPool::CGarbo gc;
    int main()
    {
    //    MemoryPool pool1;
        //MemoryPool pool2;
        void* ptr1=MemoryPool::GetInstance()->Alloc(10);
        MemoryPool::GetInstance()->Dealloc(ptr1);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
  • 相关阅读:
    论文笔记: 图神经网络 GAT
    智能运维实战:银行业务流程及单笔交易追踪
    eclipse svn插件安装
    【FreeSwitch开发实践】使用SIP客户端Yate连接FreeSwitch进行VoIP通话
    Kubernetes 深入理解kubernetes(一)
    工程管理系统源码之全面+高效的工程项目管理软件
    华为公司 java 面试题
    python 如何解析含有重复key的json
    iOS OC项目中引入SwiftUI文件
    rust下载文件
  • 原文地址:https://blog.csdn.net/weixin_62684026/article/details/128049460