C++11标准下的单例设计模式
Posted AllenSquirrel
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++11标准下的单例设计模式相关的知识,希望对你有一定的参考价值。
单例设计模式
设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。
为什么会产生设计模式这样的东西呢?
使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。
其中最具代表性的就是单例设计模式
单例设计模式
一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息,这种方式简化了在复杂环境下的配置管理。
在linux下曾提到过单例设计模式:
实现:
- 饿汉模式:资源在程序初始化阶段就完成加载(空间换时间)
- 饿汉方法实现:
- 采用静态方法修饰资源,所有对象共用同一份资源,程序初始化阶段完成资源加载且只被加载一次
- 构造函数私有化 ,保证一个类只能实例化一个对象
template <typename T>
class Singleton {
static T data;
Singleton(){}//构造函数私有化
public:
static T* GetInstance() {
return &data;
}
};
- 懒汉模式:资源在使用的时候再去加载(延迟加载)
- 定义对象指针,初始资源为空
- static修饰,共用一份资源
- volatite修饰 ,防止编译器过度优化
- 加锁保护 线程安全
- 二次检测,防止锁冲突
template <typename T>
class Singleton {
volatite static T* inst;//定义对象指针 初始为空
static std::mutex _mutex;
public:
static T* GetInstance() {
if(inst==NULL)//double check 二次检测,避免不为空情况依然加锁,造成锁冲突
{
_mutex.lock();
if (inst == NULL) {
inst = new T();//调用时发现为空,进行获取资源
}
_mutex.unlock();
}
return inst;
}
};
总结来说,单例设计主要分为两种:
- 饿汉模式(提前响应)
- 懒汉模式(延迟加载)
-
饿汉模式
在C++11标准下,饿汉模式要求:程序启动时就创建一个唯一的实例对象
要满足此条件,提前创建对象,只有将其定义为全局变量或静态变量,才会程序启动前完成创建
// 饿汉模式
// 优点:简单
// 缺点:可能会导致进程启动慢,且如果有多个单例类对象实例启动顺序不确定。
class Singleton
{
public:
static Singleton* GetInstance()
{
return &m_instance;
}
private:
// 构造函数私有
Singleton(){};
// C++11防拷贝
Singleton(Singleton const&) = delete;
Singleton& operator=(Singleton const&) = delete;
static Singleton m_instance;
};
Singleton Singleton::m_instance; // 在程序入口之前就完成单例对象的初始化
注:
1,构造函数私有 外部无法创建对象
2,通过接口 指针获取已创建对象
3,类内 定义静态成员对象,类外初始化
4,定义静态成员,静态成员定义在类内,类内可以访问私有成员函数完成构造,且静态成员存储在静态数据区,与类不为同一块存储空间
-
懒汉模式
#include <iostream>
#include <mutex>
#include <thread>
using namespace std;
class Singleton
{
public:
static Singleton* GetInstance() {
// 注意这里一定要使用Double-Check的方式加锁,才能保证效率和线程安全
if (nullptr == m_pInstance) {//第一次判断防止多次加锁导致锁冲突
m_mtx.lock();
if (nullptr == m_pInstance) {//第二次判断是否为空,为空则为第一次调用构造函数创建,不为空,后续都不会调用构造函数,满足对象第一次创建且仅创建一次
m_pInstance = new Singleton();
}
m_mtx.unlock();
}
return m_pInstance;
}
// 实现一个内嵌垃圾回收类
class CGarbo {
public:
~CGarbo(){
if (Singleton::m_pInstance)
delete Singleton::m_pInstance;
}
};
// 定义一个静态成员变量,程序结束时,系统会自动调用它的析构函数从而释放单例对象
static CGarbo Garbo;
private:
// 构造函数私有
Singleton(){};
// 防拷贝
Singleton(Singleton const&);
Singleton& operator=(Singleton const&);
static Singleton* m_pInstance; // 单例对象指针 静态成员变量,在调用构造函数前先创建进行判断
static mutex m_mtx; //互斥锁
};
Singleton* Singleton::m_pInstance = nullptr;//静态成员变量类外初始化,第一次初始化为nullptr
Singleton::CGarbo Garbo;
mutex Singleton::m_mtx;
void func(int n)
{
cout<< Singleton::GetInstance() << endl;
}
// 多线程环境下演示上面GetInstance()加锁和不加锁的区别。
int main()
{
thread t1(func, 10);
thread t2(func, 10);
t1.join();
t2.join();
cout << Singleton::GetInstance() << endl;
cout << Singleton::GetInstance() << endl;
}
以上是关于C++11标准下的单例设计模式的主要内容,如果未能解决你的问题,请参考以下文章