网站按城市做分站,wordpress c博客,宁波网站建设有限公司,公司做网站的费用入账一、单例模式 单例模式(Singleton Pattern)#xff0c;使用最广泛的设计模式之一。其意图是保证一个类仅有一个实例被构造#xff0c;并提供一个访问它的全局访问接口#xff0c;该实例被程序的所有模块共享。 1、饿汉式
1.1、基础版本 在程序启动后立刻构造单例#xff0…一、单例模式 单例模式(Singleton Pattern)使用最广泛的设计模式之一。其意图是保证一个类仅有一个实例被构造并提供一个访问它的全局访问接口该实例被程序的所有模块共享。 1、饿汉式
1.1、基础版本 在程序启动后立刻构造单例饿汉式实现一个单例类步骤如下 定义一个单例类私有化构造函数防止外界直接创建单例类的对象禁用拷贝构造移动赋值等函数可以私有化也可以直接使用delete使用一个公有的静态方法获取该实例确保在第一次调用之前该实例被构造 代码实现 #include iostream
#include string
using namespace std;// 单例类
class Singleton {
protected:Singleton() { std::cout Singleton: call Constructor\n; };static Singleton *m_pInst;public:Singleton(const Singleton ) delete;Singleton operator(const Singleton ) delete;virtual ~Singleton() { std::cout Singleton: call Destructor\n; }static Singleton* GetInstance() {return m_pInst;}
};Singleton *Singleton::m_pInst new Singleton;int main()
{Singleton *pInst1 Singleton::GetInstance();Singleton *pInst2 Singleton::GetInstance();cout pInst1 : pInst1 endl;cout pInst2 : pInst2 endl;return 0;
}输出结果 Singleton: call Constructor
pInst1 : 0xf71760
pInst2 : 0xf71760Process returned 0 (0x0) execution time : 0.203 s
Press any key to continue.从输出结果可以看出来在执行main函数之前单例类对象已经被创建出来。获取实例的函数也不需要进行判空操作因此也就不用双重检测锁来保证线程安全了它本身已经是线程安全状态了但是内存泄漏的问题还是要解决的。 1.2、基于资源管理的饿汉实现 内存泄漏解决方法有两个智能指针静态嵌套类。 1.2.1、智能指针解决方案 将实例指针更换为智能指针另外智能指针在初始化时还需要添加公有的销毁函数因为析构函数私有化了。 #include iostream
#include string
#include mutex
#include memory
#include thread
using namespace std;// 单例类
class Singleton {
protected:Singleton() { std::cout Singleton: call Constructor\n; };static shared_ptrSingleton instance;private:Singleton(const Singleton ) delete;Singleton operator(const Singleton ) delete;virtual ~Singleton() { std::cout Singleton: call Destructor\n; }public:// 自定义销毁实例方法static void DestoryInstance(Singleton* x) {delete x;}static shared_ptrSingleton GetInstance() {return instance;}
};// 初始化
shared_ptrSingleton Singleton::instance(new Singleton(), DestoryInstance);int main()
{cout main开始 endl;thread t1([] {shared_ptrSingleton s1 Singleton::GetInstance();});thread t2([] {shared_ptrSingleton s2 Singleton::GetInstance();});t1.join();t2.join();cout main结束 endl;return 0;
} 输出结果 Singleton: call Constructor
main开始
main结束
Singleton: call DestructorProcess returned 0 (0x0) execution time : 0.116 s
Press any key to continue.从输出结果可以看出来实例内存在程序运行结束后被正常释放。 1.2.2、静态嵌套类解决方案 类中定义一个嵌套类初始化该类的静态对象当程序结束时该对象进行析构的同时将单例实例也删除了。 #include iostream
#include string
#include mutex
#include memory
#include thread
using namespace std;// 单例类
class Singleton {// 定义一个删除器嵌套类class Deleter {public:Deleter() {};~Deleter() {if (m_pInst ! nullptr) {cout 删除器启动 endl;delete m_pInst;m_pInst nullptr;}}};protected:Singleton() { std::cout Singleton: call Constructor\n; };static Deleter m_deleter;static Singleton* m_pInst;private:Singleton(const Singleton ) delete;Singleton operator(const Singleton ) delete;virtual ~Singleton() { std::cout Singleton: call Destructor\n; }public:static Singleton* GetInstance() {return m_pInst;}
};Singleton *Singleton::m_pInst new Singleton;
Singleton::Deleter Singleton::m_deleter;int main()
{cout main开始 endl;thread t1([] {Singleton *pInst1 Singleton::GetInstance();});thread t2([] {Singleton *pInst2 Singleton::GetInstance();});t1.join();t2.join();cout main结束 endl;return 0;
} 输出结果 Singleton: call Constructor
main开始
main结束
删除器启动
Singleton: call DestructorProcess returned 0 (0x0) execution time : 0.254 s
Press any key to continue.从输出结果可以看出来单例类对象在程序运行结束时正常被释放。 2、懒汉式
2.1、基础版本 在使用类对象单例实例时才会去创建实现如下 #include iostream
#include string
#include mutex
#include memory
#include thread
using namespace std;// 单例类
class Singleton
{
public:static Singleton* GetInstance() {if (m_pInst nullptr) {m_pInst new Singleton;}return m_pInst;}private:// 私有构造函数Singleton() { cout 构造函数启动。 endl; };// 私有析构函数~Singleton() { cout 析构函数启动。 endl; };private:static Singleton* m_pInst;
};// 初始化
Singleton* Singleton::m_pInst nullptr;int main()
{cout main开始 endl;thread t1([] {Singleton *pInst1 Singleton::GetInstance();});thread t2([] {Singleton *pInst2 Singleton::GetInstance();});t1.join();t2.join();cout main结束 endl;return 0;
} 上面的懒汉式存在两方面问题一是多线程场景存在并发问题二是创建的单例对象在使用完成后不会被释放存在资源泄露问题。 2.2、双重检查 使用双重检查解决多线程并发问题核心代码如下 static Singleton* GetInstance() {if (m_pInst nullptr) {// 双重检查lock_guardmutex l(m_mutex);if (m_pInst nullptr) {m_pInst new Singleton();}}return m_pInst;
}双重检查能解决多线程并发问题同时效率也比单检查要高调用GetInstance时只有当单例对象没有被创建时才会加锁下面是单检查的实现通过对比即可发现双检查的优点如下 static Singleton* GetInstance() {lock_guardmutex l(m_mutex);if (m_pInst nullptr) {m_pInst new Singleton();}return m_pInst;
}2.3、基于静态局部对象的实现 C11后规定了局部静态对象在多线程场景下的初始化行为只有在首次访问时才会创建实例后续不再创建而是获取。若未创建成功其他的线程在进行到这步时会自动等待。注意C11前的版本不是这样的。因为有上述的改动所以出现了一种更简洁方便优雅的实现方法基于局部静态对象实现如下 #include iostream
#include string
#include mutex
#include memory
#include thread
using namespace std;// 单例类
class Singleton
{
public:static Singleton* GetInstance() {static Singleton instance;return instance;}private:// 私有构造函数Singleton() { cout 构造函数启动。 endl; };// 私有析构函数~Singleton() { cout 析构函数启动。 endl; };
};int main()
{cout main开始 endl;thread t1([] {Singleton *pInst1 Singleton::GetInstance();});thread t2([] {Singleton *pInst2 Singleton::GetInstance();});t1.join();t2.join();cout main结束 endl;return 0;
}