单例模式
1. 什么是单例模式
单例模式(Singleton Pattern,也称为单件模式),使用最广泛的设计模式之一。其意图是保证一个类仅有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。
定义一个单例类:
- 私有化它的构造函数,以防止外界创建单例类的对象;
- 使用类的私有静态指针变量指向类的唯一实例;
- 使用一个公有的静态方法获取该实例。
2.懒汉版
static Singleton* getInstance() { if(instance == NULL) { Lock lock; // 基于作用域的加锁,超出作用域,自动调用析构函数解锁 if(instance == NULL) { instance = new Singleton(); } } return instance; }
instance = new Singleton()可以分为3步:
1.分配一块空间
2.调用构造器构造对象
3.这块空间赋值给instance
意外情况:
正常的123执行顺序变成了132,线程执行到13时时间片结束,挂起,下一次另一个线程执行到
if(instance == NULL)
此时不为空,返回instace,但是这个instance还没有构造出来,导致出错。
C++11中的atomic类的默认memory_order_seq_cst保证了3、6行代码的正确同步
atomic<Widget*> Widget::pInstance{ nullptr }; Widget* Widget::Instance() { if (pInstance == nullptr) { lock_guard<mutex> lock{ mutW }; if (pInstance == nullptr) { pInstance = new Widget(); } } return pInstance; }
Best of All:
C++11规定了local static在多线程条件下的初始化行为,要求编译器保证了内部静态变量的线程安全性。在C++11标准下,《Effective C++》提出了一种更优雅的单例模式实现,使用函数内的 local static 对象。这样,只有当第一次访问getInstance()
方法时才创建实例。这种方法也被称为Meyers' Singleton。C++0x之后该实现是线程安全的,C++0x之前仍需加锁。
// version 1.2 class Singleton { private: Singleton() { }; ~Singleton() { }; Singleton(const Singleton&); Singleton& operator=(const Singleton&); public: static Singleton& getInstance() { static Singleton instance; return instance; } };
3. 饿汉版(Eager Singleton)
饿汉版(Eager Singleton):指单例实例在程序运行时被立即执行初始化
// version 1.3 class Singleton { private: static Singleton instance; private: Singleton(); ~Singleton(); Singleton(const Singleton&); Singleton& operator=(const Singleton&); public: static Singleton& getInstance() { return instance; } } // initialize defaultly Singleton Singleton::instance;
有些内容转载自知乎:
C++ 单例模式
https://zhuanlan.zhihu.com/p/37469260