单例模式:
- 一个类只能创建一个对象,即单例模式,该模式可以保证系统中只有一个实例,并提供一个访问它的安全局访问点,该实例被所有程序模块共享。用于管理服务器配置;
构造函数私有化/防拷贝
构造函数私有化/与防拷贝是实现懒汉饿汉的必要手段,如果你已经了然于心,请直接跳到下一部分:
- 构造函数私有化:将类的构造函数私有,拷贝构造声明私有。防止别人拷贝在栈上生成对象。
- 防拷贝:考虑也得限制拷贝对象,因为不限制,拷贝时可以直接调用默认构造-
- 基于C98在:在私有类只声明拷贝构造不实现;
- 基于C11:删除函数,“函数=delete”任何情况都不可以用;
- 用一个具体的例子,看看它们是具体如何实现的:
设计一个类,该类只能在堆上创建对象(只能用new去申请) - 将构造函数私有化,这样别人无法直接在外部创建对象,之能那个我规定好的在堆上申请空间的函数申请。使用提供一个静态成员函数,在该静态成员函数中完成堆对象的创建,防拷贝,别人也可以通过拷贝构造钻空子访问,注意基于C89的在私有类让拷贝构造只声明不实现方法若是遇到友元函数,就会出现漏洞,所以在这里我们使用C11的特性-删除函数;
class Heap{
public:
static Heap* GetHeap(){
return new Heap;
}
private:
Heap()
{}//构造声明为私有,将不在对外开放;
//Heap(const Heap&b);//
Heap(const Heap&b) = delete//删除函数
};//C11
int main(){
Heap*p1 = Heap::GeatHeap();
return 0;
}
饿汉模式
- 就是不管你将来用不用,启动程序时就创建一个唯一的实例对象(哇我三天没吃了,一看见吃的立马消灭!)
- 如果这个单例对象在多线程高并发环境下频繁使用,性能要求较高,那么显然使用饿汉模式来避免资源竞争,提高响应速度更好。
- 优点:简单;缺点:可能会导致启动很慢;
- 要点:只能创建单个实例所以构造私有化/防拷贝
class Singleton{
public:
static Singleton* GetInstance(){//获取实例;
return &_sInstance;
}
private:
Singleton()
{}
//防拷贝;
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
static Singleton _sInstance;
};
Singleton Singleton::_sInstance;//在程序入口之前就完成单例对象初始化;
int main(){
return 0;
}
懒汉模式
- 需要用到该对象了再创建,(急什么,放兜里饿了再吃嘛!)
- 如果单例对象构造十分耗时或者占用很多资源,比如加载插件,初始化网络连接,读取文件等,而可能该对象运行时不会用到,那麽也要在程序一开始就进行初始化,就会导致程序启动时非常缓慢。所以此情况使用懒汉模式(延迟加载)更好;
- 优点:第一次使用实例时创建,启动时间短;缺点:复杂
- 要点:防拷贝/线程安全(加锁)/double check(创建实例后,不再进行加锁解锁)提高效率/注意回收
class Singleton{
public:
static Singleton* GetInstance(){//获取实例;
if(nullptr ==_sInstance){//双检查:当对象已经有了,就不再进行枷锁解锁了(会有消耗,且并行会变成串行,性能下降),双检查会提高效率,减少浪费;
m_mtx.lock();//加互斥锁,t1进去后会上锁,t2就得等到t1解锁后才行;不加若是同时检测到空,创建两个对象,就不是单例了,线程不安全;
if(_sInstance==nullptr){//第一次使用的时候才初始化创建;
_sInstance=new Singleton;
}
m_mtx.unlock();//解锁;
}
return _sInstance;
}
class CGarbo {//实现内部类实现垃圾回收功能
public:
~CGarbo(){
if (Singleton::_sInstance)
delete Singleton::_sInstance;
}
};
private:
Singleton()
{}
//单例防拷贝;
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
static CGarbo Garbo;//定义一个静态成员变量,main程序结束时,系统会释放静态变量,会自动调用它的析构函数从而释放单例对象;
static Singleton* _sInstance;//单例对象指针
static mutex m_mtx;//加互斥锁
};
Singleton* Singleton::_sInstance=nullptr;
Singleton::CGarbo Singleton::Garbo;//初始化类对象会自动调缺省构造
mutex Singleton::m_mtx;
void func(int n){
cout<< Singleton::GetInstance() << endl;
}
int main(){
thread t1(func, 10);//创建多个线程
thread t2(func, 10);
t1.join();//本程序t等一下t1,t2,不可在t1,t2之前结束;
t2.join();
cout << Singleton::GetInstance() << endl;
cout << Singleton::GetInstance() << endl;
}
yo~
yo~
如果觉得不错~
请别忘了点个赞~
Bro你的鼓励~
给我坚持的勇气~
Peace out~