设计模式 -- 把简单的代码复杂化 -- 方便后期维护
单例模式:
一般情况下,用户可以通过类构造很多个对象
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 }
推荐: