在C++中,单例模式是一种设计模式,用于确保一个类只有一个实例,并提供一个全局访问点来访问该实例。可以通过静态成员变量和静态成员函数来实现单例模式。单例模式的核心目的就是确保在程序运行期间只能存在一个实例对象。
目录
一、单例模式作用说明
单例模式的作用是确保一个类只有一个实例,并提供一个全局访问点来访问该实例。这种模式通常用于需要全局访问点的情况,比如日志记录器、配置管理器、数据库连接等。通过单例模式,可以避免多个实例的创建和占用过多系统资源,同时也可以确保数据的一致性和避免多线程环境下的竞态条件。
二、单例模式-饿汉模式
饿汉模式是一种单例模式的实现方式,即在程序启动时就创建并初始化单例对象,而不是在需要时再进行延迟加载。这样可以确保在程序运行过程中始终只有一个实例对象。
1.饿汉模式的实现
class Singleton
{
public:
static Singleton* GetInstance() //通过调用GetInstance() 在类外获得实例
{
return &_slt; //返回这个实例的地址
}
void print() //输出实例的数据
{
cout << _x << " " << _y << endl;
for (auto e : _vect)
{
cout << e << " ";
}
cout << endl;
}
void Add_Vect(int n) //对实例的Vector进行尾插
{
_vect.push_back(n);
}
private:
int _x;
int _y;
vector<int>_vect;
static Singleton _slt; //类内声明
//因为要实现单例类(全局只能有一个对象,因此要将构造函数私有化否则可以在类外随便创建)
Singleton(int x = 1, int y = 1, const vector<int>& v = { 1,2,3,4,5 })
:_x(x)
, _y(y)
, _vect(v)
{}
//禁用拷贝构造和赋值重载
Singleton(const Singleton& hs) = delete;
Singleton& operator=(const Singleton& hs) = delete;
};
//类外初始化
Singleton Singleton::_slt(2, 2,{ 4,5,6 });
//测试懒汉
void Test01()
{
//Singleton::GetInstance()返回创建静态对象的指针
Singleton::GetInstance()->print();
Singleton::GetInstance()->print();
cout << "对象1的地址为:" << Singleton::GetInstance() << endl;
cout << "对象2的地址为:" << Singleton::GetInstance() << endl;
//结果为:
//2 2
//4 5 6
//后面两个地址是一样的(也就是返回的都是同一个实例)
}
2.饿汉模式的理解
1.什么是饿汉模式?
饿汉模式,这个名词很形象,大家可以想象为很“饥饿”,实例在类加载的时候就被创建,所以一开始还没有进入到main函数中就要创建实例。
2.为什么要把构造函数、拷贝构造和赋值构造设为私有和禁用呢?
因为要实现单例模式,所以我们一定要把构造函数私有化,因为只有这样,才可以避免在类外随意创建对象 (私有函数在类外是无法访问的。)
3.如何实现饿汉模式?
饿汉模式就是要一开始就创建实例,所以用静态成员变量实现(在类加载时就创建)。
二、单例模式-懒汉模式
懒汉模式,这个名词也很形象,大家可以想象为很“懒”,实例在调用的时候才开始创建。
1.懒汉模式的实现
class Singleton
{
public:
static Singleton* GetInstance() //必须定义为静态函数因为只有这样才可以不创建对象去调用它来创建对象
{ //否则所有成员函数要通过对象去调用(若不设置为静态的无法创建出来对象(构造函数私有了))
static Singleton slt(2, 2, {7,8,9}); //静态函数每次只会初始化一次 所以只会在第一次调用时初始化
return &slt; //下次调用GetInstance()会直接返回&slt
}
void print()
{
cout << _x << " " << _y << endl;
for (auto e : _vect)
{
cout << e << " ";
}
cout << endl;
}
void Add_Vect(int n)
{
_vect.push_back(n);
}
private:
int _x;
int _y;
vector<int>_vect;
//因为要实现单例类(全局只能有一个对象,因此要将构造函数私有化否则可以在类外随便创建)
Singleton(int x = 1, int y = 1, const vector<int>& v = { 1,2,3,4,5 })
:_x(x)
, _y(y)
, _vect(v)
{}
//禁用拷贝构造和赋值重载
Singleton(const Singleton& hs) = delete;
Singleton& operator=(const Singleton& hs) = delete;
};
//测试懒汉
void Test01()
{
//Singleton::GetInstance()返回创建静态对象的指针
Singleton::GetInstance()->print();
Singleton::GetInstance()->print();
cout << "对象1的地址为:" << Singleton::GetInstance() << endl;
cout << "对象2的地址为:" << Singleton::GetInstance() << endl;
//结果为:(因为调用两次所以打印两次)
//2 2
//7 8 9
//2 2
//7 8 9
//后面两个地址是一样的
}
2.懒汉模式的理解
三、饿汉模式和懒汉模式的优缺点
1.饿汉模式的优缺点
饿汉模式的优点:
- 线程安全:在类加载的时候就创建实例,不存在多线程环境下的线程安全问题(还没进入主函数就创建完实例了,所以不用担心线程安全问题)。
饿汉模式的缺点:
- 可能会造成资源浪费:在程序运行过程中始终存在实例,可能会占用一定的资源。
- 不支持延迟加载:无法实现延迟加载的特性。
2.懒汉模式的优缺点
懒汉模式的优点:
- 延迟加载:在第一次调用时才创建实例,节省资源。
- 节约内存:只有在需要时才创建实例,避免资源浪费。
懒汉模式的缺点:
- 线程安全性问题:在多线程环境下,需要额外的同步措施来保证线程安全。
- 可能存在性能问题:在第一次调用时需要进行实例化,可能会影响程序性能。
总结
以上是我对单例模式-饿汉和懒汉模式的理解,希望可以对大家有所帮助。