单例模式实际上就是为了确保一个类最多只有一个实例,并且在程序的任何地方都可以访问这个实例,也就是提供一个全局访问点,单例对象不需要手动释放,交给系统来释放就可以了,单例模式的设计初衷就是为了在整个应用程序的生命周期中只创建一个实例,并且在需要时重复使用该实例,而不是频繁地创建和销毁对象。因此,在应用程序运行期间,单例对象通常会一直存在,直到应用程序结束。
一般来说,实现单例模式的方式有两种,一种是懒加载的方式,另外一种是预加载的方式。
实际上实现单例模式的基本步骤其实是一样的。第一步都是将构造函数和析构函数私有化,然后定义一个静态单例对象和声明一个静态单例对象获取函数,最后初始化单例对象和定义单例对象获取函数。
懒加载:当使用到单例对象的时候,才创建这个对象。
main函数
cpp
#include"Test.h"
#include<iostream>
int main()
{
Test*t1=Test::get_instance();
Test*t2=Test::get_instance();
std::cout<<"t1:"<<t1<<std::endl;
std::cout<<"t2:"<<t2<<std::endl;
return 0;
}
Test.h
将构造函数私有化 ,可以阻止外部代码直接实例化类的对象,强制使用单例模式提供的静态方法来获取类的唯一实例。这样可以确保在整个应用程序中只有一个实例存在。通过私有化析构函数,可以防止外部代码直接删除单例对象,从而确保单例对象在整个应用程序的生命周期内保持存在。这有助于避免意外的对象销毁和内存泄漏。
将单例对象(t_instance)声明为静态的是为了确保单例对象的唯一性、全局访问性和简化访问方式。静态单例对象可以在整个应用程序中被直接访问,避免多次实例化的情况发生,符合单例模式的设计原则
cpp
class Test
{
public:
static Test*get_instance();
private:
Test();
~Test();
static Test*t_instance;
};
Test.cpp
cpp
#include"Test.h"
Test*Test::t_instance=nullptr;
Test *Test::get_instance()
{
if(t_instance==nullptr)
{
t_instance=new Test();
}
return t_instance;
}
Test::Test()
{
}
Test::~Test()
{
delete t_instance;
}
运行代码,可以发现,两个Test对象的地址是一样的,也就是说明这两个对象是同一个对象。
上面这种写法的懒加载其实是线程不安全的,当多个线程调用get_instance函数时,可能会创建出多个对象,将单例获取函数改进一下就可以了。
cpp
#include<mingw.mutex.h>
class Test
{
public:
static Test*get_instance();
private:
Test();
~Test();
static Test*t_instance;
static std::mutex tmutex;
};
cpp
#include"Test.h"
Test*Test::t_instance=nullptr;
std::mutex Test::tmutex;
Test *Test::get_instance()
{
if(t_instance==nullptr)
{
std::lock_guard<std::mutex>lk(tmutex);
t_instance=new Test();
}
return t_instance;
}
Test::Test()
{
}
Test::~Test()
{
delete t_instance;
}
预加载:程序启动的时候,就将对象创建好。
只需要更改懒加载的Test.cpp就可以了,不必判断单例对象是否为空,在类被第一次使用的时候就直接创建好了单例对象。
cpp
#include"Test.h"
Test*Test::t_instance=new Test();
Test *Test::get_instance()
{
return t_instance;
}
Test::Test()
{
}
Test::~Test()
{
delete t_instance;
}