单例模式 C++
单例模式(Singleton Pattern,也称为单件模式),是保证一个类仅有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。也就是在任何位置都可以通过接口获取到那个唯一实例。
定义一个单例类:
私有化它的构造函数,以防止外界创建单例类的对象;
使用类的私有静态指针变量指向类的唯一实例;
使用一个公有的静态方法获取该实例。
单例模式适用于以下情况:
需要全局访问点:当一个对象需要在整个程序中被访问时,可以使用单例模式确保只有一个实例存在,并提供一个全局访问点。
资源共享:单例模式可以用来管理共享的资源,例如数据库连接、日志文件等,确保在程序的生命周期中只有一个实例存在,避免资源浪费和冲突。
控制实例个数:有些情况下,需要限制一个类只能有一个实例,这时单例模式非常有用。
延迟实例化:有时候希望对象的实例在第一次被访问时才被创建,单例模式可以实现延迟实例化,提高程序的性能。
线程池、缓存、对话框、注册表设置:在这些情景下,单例模式可以有效地管理资源或状态,确保在程序中只有一个实例存在。
局部静态变量
我们知道当一个函数中定义一个局部静态变量,那么这个局部静态变量只会初始化一次,就是在这个函数第一次调用的时候,以后无论调用几次这个函数,函数内的局部静态变量都不再初始化。 因此可以利用局部静态变量这一特点来实现单例。
//懒汉式
class Single {
private:
Single()
{
}
Single(const Single&) = delete;
Single& operator=(const Single&) = delete;
public:
static Single& GetInst()
{
static Single single;
return single;
}
};
void test_single()
{
//C11之前多线程情况下可能存在问题
cout << "s1 addr is " << &Single::GetInst() << endl;
cout << "s2 addr is " << &Single::GetInst() << endl;
}
程序输出如下
sp1 is 0x1304b10
sp2 is 0x1304b10
静态成员变量指针方式
//饿汉式
class Single2Hungry
{
private:
Single2Hungry()
{
}
Single2Hungry(const Single2Hungry &) = delete;
Single2Hungry &operator=(const Single2Hungry &) = delete;
public:
static Single2Hungry *GetInst()
{
if (single == nullptr)
{
single = new Single2Hungry();
}
return single;
}
private:
static Single2Hungry *single;
};
饿汉式的方式可以避免线程安全问题
//饿汉式初始化
Single2Hungry *Single2Hungry::single = Single2Hungry::GetInst();
void thread_func_s2(int i)
{
cout << "this is thread " << i << endl;
cout << "inst is " << Single2Hungry::GetInst() << endl;
}
void test_single2hungry()
{
cout << "s1 addr is " << Single2Hungry::GetInst() << endl;
cout << "s2 addr is " << Single2Hungry::GetInst() << endl;
for (int i = 0; i < 3; i++)
{
thread tid(thread_func_s2, i);
tid.join();
}
}
int main(){
test_single2hungry()
}
程序输出
s1 addr is 0x1e4b00
s2 addr is 0x1e4b00
this is thread 0
inst is 0x1e4b00
this is thread 1
inst is 0x1e4b00
this is thread 2
inst is 0x1e4b00
单线程还是多线程模式下,通过静态成员变量的指针实现的单例类都是唯一的。
无论饿汉式还是懒汉式都存在一个问题,就是什么时候释放内存?多线程情况下,释放内存就很难了,还有二次释放内存的风险。
智能指针方式
利用智能指针自动回收内存的机制设计单例类
//safe deletor
//防止外界delete
//声明辅助类
//该类定义仿函数调用SingleAutoSafe析构函数
//不可以提前声明SafeDeletor,编译时会提示incomplete type
// class SafeDeletor;
//所以要提前定义辅助类
class SingleAutoSafe;
class SafeDeletor
{
public:
void operator()(SingleAutoSafe *sf)
{
cout << "this is safe deleter operator()" << endl;
delete sf;
}
};
class SingleAutoSafe
{
private:
SingleAutoSafe() {}
~SingleAutoSafe()
{
cout << "this is single auto safe deletor" << endl;
}
SingleAutoSafe(const SingleAutoSafe &) = delete;
SingleAutoSafe &operator=(const SingleAutoSafe &) = delete;
//定义友元类,通过友元类调用该类析构函数
friend class SafeDeletor;
public:
static std::shared_ptr<SingleAutoSafe> GetInst()
{
if (single != nullptr)
{
return single;
}
s_mutex.lock();
if (single != nullptr)
{
s_mutex.unlock();
return single;
}
//额外指定删除器
single = std::shared_ptr<SingleAutoSafe>(new SingleAutoSafe, SafeDeletor());
//也可以指定删除函数
// single = std::shared_ptr<SingleAutoSafe>(new SingleAutoSafe, SafeDelFunc);
s_mutex.unlock();
return single;
}
private:
static std::shared_ptr<SingleAutoSafe> single;
static mutex s_mutex;
};
通用的单例模板类
template <typename T>
class Single_T
{
protected:
Single_T() = default;
Single_T(const Single_T<T> &st) = delete;
Single_T &operator=(const Single_T<T> &st) = delete;
~Single_T()
{
cout << "this is auto safe template destruct" << endl;
}
public:
static std::shared_ptr<T> GetInst()
{
if (single != nullptr)
{
return single;
}
s_mutex.lock();
if (single != nullptr)
{
s_mutex.unlock();
return single;
}
//额外指定删除器
single = std::shared_ptr<T>(new T, SafeDeletor_T<T>());
//也可以指定删除函数
// single = std::shared_ptr<SingleAutoSafe>(new SingleAutoSafe, SafeDelFunc);
s_mutex.unlock();
return single;
}
private:
static std::shared_ptr<T> single;
static mutex s_mutex;
};
//模板类的static成员要放在h文件里初始化
template <typename T>
std::shared_ptr<T> Single_T<T>::single = nullptr;
template <typename T>
mutex Single_T<T>::s_mutex;
评论区