什么是设计模式
设计模式代表了最佳实践,是软件开发过程中面临一般问题的解决方案。
设计模式是一套被反复使用、经过分类、代码设计总结的经验。
单例模式
单例模式也叫单件模式。Singleton是一个非常常用的设计模式,几乎所有稍微大一些的程序都会使用到它,所以构建一个线程安全并且高效的Singleton很重要。
1. 单例类保证全局只有一个唯一实例对象。
2. 单例类提供获取这个唯一实例的接口。
怎样设计一个单例模式
实现一(不考虑线程安全)
class Singleton
{
public:
// 获取唯一对象实例的接口函数
static Singleton* GetInstance()
{
if(_sInstance == NUL)
{
if (_sInstance == NULL)
{
_sInstance = new Singleton();
}
}
return _sInstance;
}
// 删除实例对象
static void DelInstance()
{
if (_sInstance)
{
delete _sInstance;
_sInstance = NULL;
}
}
void Print()
{
cout<<_data<<endl;
}
private:
// 构造函数定义为私有,限制只能在类内创建对象
Singleton()
:_data(0)
{}
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
// 指向实例的指针定义为静态私有,这样定义静态成员函数获取对象实例
static Singleton* _sInstance;
// 单例类里面的数据
int _data;
};
Singleton* Singleton::_sInstance = NULL;
void TestSingleton()
{
Singleton::GetInstance()->Print();
Singleton::DelInstance();
}
实现二
线程安全的单例 -- (懒汉模式-- lazy loading)
ps: 下面部分的加锁使用了C++11库的互斥锁
class Singleton
{
public:
// 获取唯一对象实例的接口函数
static Singleton* GetInstance()
{
// 使用双重检查,提高效率,避免高并发场景下每次获取实例对象都进行加锁
if (_sInstance == NULL)
{
std::lock_guard<std::mutex> lck(_mtx);
if (_sInstance == NULL)
{
// tmp = new Singleton()分为以下三个部分
// 1.分配空间 2.调用构造函数 3.赋值
// 编译器编译优化可能会把2和3进行指令重排,这样可能会导致
// 高并发场景下,其他线程获取到未调用构造函数初始化的对象
// 以下加入内存栅栏进行处理,防止编译器重排栅栏后面的赋值
// 到内存栅栏之前
Singleton* tmp = new Singleton();
MemoryBarrier();
_sInstance = tmp;
}
}
return _sInstance;
}
// 删除实例对象
static void DelInstance()
{
std::lock_guard<std::mutex> lck(_mtx);
if (_sInstance)
{
delete _sInstance;
_sInstance = NULL;
}
}
void Print()
{
cout<<_data<<endl;
}
private:
// 构造函数定义为私有,限制只能在类内创建对象
Singleton()
:_data(0)
{}
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
// 指向实例的指针定义为静态私有,这样定义静态成员函数获取对象实例
static Singleton* _sInstance;
// 保证线程安全的互斥锁
static mutex _mtx;
// 单例类里面的数据
int _data;
};
Singleton* Singleton::_sInstance = NULL;
mutex Singleton::_mtx;
void TestSingleton()
{
Singleton::GetInstance()->Print();
Singleton::DelInstance();
}
线程安全的单例 -- (饿汉模式--简洁、高效、不用加锁、但是在某些场景下会有缺陷)
方法1
// 方式一
class Singleton
{
public:
// 获取唯一对象实例的接口函数
static Singleton* GetInstance()
{
static Singleton sInstance;
return &sInstance;
}
void Print()
{
cout<<_data<<endl;
}
private:
// 构造函数定义为私有,限制只能在类内创建对象
Singleton()
:_data(0)
{}
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
// 单例类里面的数据
int _data;
};
void TestSingleton()
{
Singleton::GetInstance()->Print();
}
// 方式二
class Singleton
{
public:
// 获取唯一对象实例的接口函数
static Singleton* GetInstance()
{
assert(_sInstance);
return _sInstance;
}
// 删除实例对象
static void DelInstance()
{
if (_sInstance)
{
delete _sInstance;
_sInstance = NULL;
}
}
void Print()
{
cout << _data << endl;
}
private:
// 构造函数定义为私有,限制只能在类内创建对象
Singleton()
:_data(0)
{}
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
// 指向实例的指针定义为静态私有,这样定义静态成员函数获取对象实例
static Singleton* _sInstance;
// 单例类里面的数据
int _data;
};
Singleton* Singleton::_sInstance = new Singleton;
void TestSingleton()
{
Singleton::GetInstance()->Print();
Singleton::DelInstance();
}
class Singleton
{
public:
// 获取唯一对象实例的接口函数
static Singleton* GetInstance()
{
assert(_sInstance);
return _sInstance;
}
// 删除实例对象
static void DelInstance()
{
if (_sInstance)
{
delete _sInstance;
_sInstance = NULL;
}
}
void Print()
{
cout << _data << endl;
}
class GC
{
public:
~GC()
{
cout << "DelInstance()"<<endl;
DelInstance();
}
};
private:
// 构造函数定义为私有,限制只能在类内创建对象
Singleton()
:_data(0)
{}
// 指向实例的指针定义为静态私有,这样定义静态成员函数获取对象实例
static Singleton* _sInstance;
// 单例类里面的数据
int _data;
};
// 静态对象在main函数之前初始化,这时只有主线程运行,所以是线程安全的。
Singleton* Singleton::_sInstance = new Singleton;
// 使用RAII,定义全局的GC对象释放对象实例
Singleton::GC gc;
void TestSingleton()
{
Singleton::GetInstance()->Print();
}
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。