• C++入门 -- 单例模式的原理与实现


    设计模式 -- 把简单的代码复杂化 -- 方便后期维护

    单例模式:

    一般情况下,用户可以通过类构造很多个对象

     1 #include <iostream>
     2 #include <string>
     3 using namespace std;
     4 
     5 class Singleton {
     6    public:
     7     Singleton() { cout << "Singleton() construct" << endl; }
     8     ~Singleton() { cout << "~Singleton() destruct" << endl; }
     9 };
    10 
    11 int main(int argc, char const *argv[]) {
    12     Singleton s1;
    13     Singleton s2;
    14     return 0;
    15 }

    如果想要用户只能实例化一个对象,该怎么作?

    将构造函数声明为private,因此外部只能通过类的成员方法来调用构造函数

    在类中实现用户唯一创建对象的一个接口CreateObj,new一个对象并返回对象的指针

    如果这个接口是普通成员函数,那么没有对象怎么调用创建对象的接口,即陷入先有鸡还是现有蛋的问题中

    那么就可以将这个接口声明为static成员函数,与对象无关,与类域相关的全局函数

    #include <iostream>
    #include <string>
    using namespace std;
    //单例模式
    class Singleton {
       public:
        ~Singleton() { cout << "~Singleton() destruct" << endl; }
        static Singleton* CreateObject() { return new Singleton(); }
    
       private:
        Singleton() { cout << "Singleton() construct" << endl; }
    };
    
    int main(int argc, char const* argv[]) {
        Singleton* p1 = Singleton::CreateObject();
        Singleton* p2 = Singleton::CreateObject();
        return 0;
    }

    接口是有了,但是调用两次接口还是生成了两个对象。

    我们可以在创建接口里对生成的对象指针进行判断,若指针为空,则new一个对象,若不为空,则返回这个指针

    因为要使这个指针不依赖与具体的对象,也要将它声明为static变量

     1 #include <iostream>
     2 #include <string>
     3 using namespace std;
     4 
     5 class Singleton {
     6    public:
     7     ~Singleton() { cout << "~Singleton() destruct" << endl; }
     8     static Singleton* CreateObject() {  //创建用户唯一的接口
     9         if (m_pObject == nullptr) {
    10             m_pObject = new Singleton();
    11         }
    12         return m_pObject;
    13     }
    14 
    15    private:
    16     Singleton() { cout << "Singleton() construct" << endl; }
    17     static Singleton* m_pObject;  
    18 };
    19 
    20 Singleton* Singleton::m_pObject = nullptr;
    21 
    22 int main(int argc, char const* argv[]) {
    23     Singleton* pObj1 = Singleton::CreateObject();
    24     Singleton* pObj2 = Singleton::CreateObject();
    25     cout << pObj1 << endl;
    26     cout << pObj2 << endl;
    27     return 0;
    28 }

    out:

     只创建了一个对象。

    但是还有内存泄漏的问题,如果释放资源,还得用户delete资源,并且这样做不是线程安全的

    在创建接口中,我们使用了new,这就会带来麻烦,创建对象还要去释放。

    所以我们在create函数中创建一个局部静态对象,并以指针的形式返回,在程序结束后,全局区的资源会自动释放

    1     static Singleton* CreateObject() {
    2         static Singleton obj;
    3         return &obj;  //返回对象的指针
    4     }

    使用指针的话,会误导用户使用delete语法来释放对象,且编译还不会报错,故此处使用引用

    如下:

     1 #include <iostream>
     2 #include <string>
     3 using namespace std;
     4 
     5 class Singleton {
     6    public:
     7     ~Singleton() { cout << "~Singleton() destruct" << endl; }
     8     // static Singleton* CreateObject() {
     9     //     if (m_pObject == nullptr) {
    10     //         m_pObject = new Singleton();
    11     //     }
    12     //     return m_pObject;
    13     // }
    14     static Singleton& CreateObject() {
    15         static Singleton obj;
    16         return obj;  //返回引用
    17     }
    18 
    19    private:
    20     Singleton() { cout << "Singleton() construct" << endl; }
    21     static Singleton* m_pObject;
    22 };
    23 
    24 Singleton* Singleton::m_pObject = nullptr;
    25 
    26 int main(int argc, char const* argv[]) {
    27     Singleton& pObj1 = Singleton::CreateObject();
    28     Singleton& pObj2 = Singleton::CreateObject();
    29     cout << &pObj1 << endl;
    30     cout << &pObj2 << endl;
    31     return 0;
    32 }

    但是这样还是会有问题,如果用户:

    27     Singleton& pObj1 = Singleton::CreateObject();
    28     Singleton  pObj2 = Singleton::CreateObject();

    28行就相当于   Singleton pObj2 =  obj;  类的拷贝构造,编译器会为类生成一个默认的构造函数,来支持类的拷贝。这样又突破单例模式的限制了

     所有我们不仅仅要限制singleton的普通构造函数,还要限制它的拷贝构造函数。禁用拷贝构造,禁用默认的运算符重载

     1 #include <iostream>
     2 #include <string>
     3 using namespace std;
     4 
     5 class Singleton {
     6    public:
     7     ~Singleton() { cout << "~Singleton() destruct" << endl; }
     8     // static Singleton* CreateObject() {
     9     //     if (m_pObject == nullptr) {
    10     //         m_pObject = new Singleton();
    11     //     }
    12     //     return m_pObject;
    13     // }
    14     static Singleton& CreateObject() {
    15         static Singleton obj;  // 会调用构造函数
    16         return obj;            //返回对象的引用
    17     }
    18     Singleton(Singleton& obj) = delete;  //禁用拷贝构造函数
    19     Singleton* operator = (Singleton& obj) = delete; //禁用默认的运算符重载
    20 
    21    private:
    22     Singleton() { cout << "Singleton() construct" << endl; }
    23     static Singleton* m_pObject;
    24 };
    25 
    26 Singleton* Singleton::m_pObject = nullptr;
    27 
    28 int main(int argc, char const* argv[]) {
    29     Singleton& pObj1 = Singleton::CreateObject();
    30     Singleton pObj2 = Singleton::CreateObject();  // Singleton pObj2 = obj;
    31     cout << &pObj1 << endl;
    32     cout << &pObj2 << endl;
    33     return 0;
    34 }

     推荐:

    C++中的单例模式

  • 相关阅读:
    vbox安装增强功能,实现宿主机文件夹共享并浏览器访问
    linux镜像下载
    linux命令之sed
    关于MySQL数据库的备份方案
    linux防火墙使用以及配置
    Jenkins安装部署(二)
    Jenkins安装部署(一)
    Centos7在虚拟机中扩展磁盘空间
    CentOS 7系统根目录分区扩容
    Linux下的SVN服务器搭建
  • 原文地址:https://www.cnblogs.com/y4247464/p/13826700.html
Copyright © 2020-2023  润新知