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++中的单例模式

原文地址:https://www.cnblogs.com/y4247464/p/13826700.html