文章目录
-
- 一、要点
- 二、代码
-
- 1.核心代码
- 2.详细注释代码
- 3.无注释代码 (单线程时,存在线程安全问题)
- 4.考虑线程安全 (getInstance加锁)
-
- [4.1 进一步减少加锁的开销,使用双重检查锁](#4.1 进一步减少加锁的开销,使用双重检查锁)
- 5.释放单例资源以避免内存泄露(智能指针)
- 6.饿汉式
一、要点
0.单例模式,顾名思义只能有一个实例对象
1.私有化构造函数 :不能随便调用构造函数来实例化对象
2.删除拷贝构造函数、赋值运算符函数 :确保唯一实例
3.使用静态成员变量,存储指向单例对象的指针 :静态方法属于类,不属于具体的实例对象。
4.提供静态方法,在堆上获取单例对象
二、代码
延迟实例化、懒加载、懒汉式:实例在第一次使用时才会被创建
1.核心代码
cpp
static Singleton* getInstance() {
if (instance == nullptr) {
instance = new Singleton(); // 只有在第一次调用时创建实例
}
return instance;
}
2.详细注释代码
cpp
#include <iostream>
using std::cout;
using std::endl;
//单例模式:要通过给的接口来创造唯一实例。
//因此,要将构造函数私有化,并且删除拷贝构造和赋值运算符函数
class Singleton
{
public:
//静态方法,用于获取唯一的实例。静态方法属于类,而非实例对象
//懒加载、懒汉式、延迟实例化
static Singleton* getInstance()
{
if(pInstance == nullptr){
pInstance = new Singleton();
}
return pInstance;
}
void display()
{
cout << "This is the Singleton instance." << "\n";
}
private:
//构造函数私有化,防止外部创建对象
Singleton()
{
cout << "Singleton instance created.\n";
}
//禁用拷贝构造和赋值运算符函数
Singleton(const Singleton & ) = delete;
Singleton & operator=(const Singleton &) = delete;
//静态成员变量,存储唯一的实例
static Singleton* pInstance;
};
//类外初始化静态成员变量
Singleton* Singleton::pInstance = nullptr;
int main()
{
//获取单例对象的唯一实例
Singleton* s1 = Singleton::getInstance();
s1->display();
//再次获取单例对象的实例
Singleton* s2 = Singleton::getInstance();
s2->display();
//验证两个指针是否指向同一个实例
if(s1 == s2){
cout << "Both pointer point to the same instance.\n";
}
return 0;
}
另一版
cpp
#include <iostream>
using std::cout;
using std::endl;
//单例模式:要通过给的接口来创造唯一实例。
//因此,要将构造函数私有化,并且删除拷贝构造和赋值运算符函数
class Singleton
{
private:
//构造函数私有化,防止外部创建对象
Singleton()
{
cout << "Singleton instance created.\n";
}
//禁用拷贝构造和赋值运算符函数
Singleton(const Singleton & ) = delete;
Singleton & operator=(const Singleton &) = delete;
//静态成员变量,存储唯一的实例
static Singleton* instance;
public:
//静态方法,用于获取唯一的实例
static Singleton* getInstance()
{
if(instance == nullptr){
instance = new Singleton(); //延迟实例化
}
return instance;
}
void display()
{
cout << "This is the Singleton instance." << "\n";
}
};
//静态成员变量初始化为nullptr
Singleton* Singleton::instance = nullptr;
int main()
{
//获取单例对象的唯一实例
Singleton* s1 = Singleton::getInstance();
s1->display();
//再次获取单例对象的实例
Singleton* s2 = Singleton::getInstance();
s2->display();
//验证两个指针是否指向同一个实例
if(s1 == s2){
cout << "Both pointer point to the same instance.\n";
}
return 0;
}
3.无注释代码 (单线程时,存在线程安全问题)
cpp
#include <iostream>
using std::cout;
using std::endl;
class Singleton
{
public:
static Singleton* getInstance()
{
if(pInstance == nullptr){
pInstance = new Singleton();
}
return pInstance;
}
private:
Singleton(){};
Singleton(const Singleton & rhs) = delete;
Singleton & operator= (const Singleton & rhs) = delete;
static Singleton* pInstance;
};
Singleton* Singleton::pInstance = nullptr;
int main()
{
Singleton* s1 = Singleton::getInstance();
Singleton* s2 = Singleton::getInstance();
if(s1 == s2){
cout << "s1 == s2,是单例的\n";
}else{
cout << "s1 != s2,不是单例的\n";
}
return 0;
}
4.考虑线程安全 (getInstance加锁)
cpp
#include <iostream>
#include <mutex>
using std::cout;
using std::mutex;
using std::lock_guard;
class Singleton
{
public:
static Singleton* getInstance()
{
lock_guard<mutex> lock(mtx);
if(pInstance == nullptr){
pInstance = new Singleton();
}
return pInstance;
}
private:
Singleton(){};
Singleton(const Singleton & rhs) = delete;
Singleton & operator= (const Singleton & rhs) = delete;
static Singleton* pInstance;
static mutex mtx; //互斥锁,确保线程安全
};
Singleton* Singleton::pInstance = nullptr;
mutex Singleton::mtx;
int main()
{
Singleton* s1 = Singleton::getInstance();
Singleton* s2 = Singleton::getInstance();
if(s1 == s2){
cout << "s1 == s2,是单例的\n";
}else{
cout << "s1 != s2,不是单例的\n";
}
return 0;
}
4.1 进一步减少加锁的开销,使用双重检查锁
cpp
// 线程安全的 getInstance 方法,使用双重检查锁
static Singleton* getInstance()
{
if(pInstance == nullptr) { // 第一次检查,无锁
std::lock_guard<std::mutex> lock(mtx); // 加锁
if(pInstance == nullptr) { // 第二次检查,加锁后
pInstance = new Singleton();
}
}
return pInstance;
}
5.释放单例资源以避免内存泄露(智能指针)
cpp
#include <iostream>
#include <mutex>
#include <memory>
using std::cout;
using std::mutex;
using std::lock_guard;
using std::unique_ptr;
class Singleton
{
public:
static Singleton* getInstance()
{
lock_guard<mutex> lock(mtx);
if(pInstance == nullptr){
/* pInstance = new Singleton(); */
pInstance = unique_ptr<Singleton>(new Singleton());
}
return pInstance.get();
}
private:
Singleton(){};
Singleton(const Singleton & rhs) = delete;
Singleton & operator= (const Singleton & rhs) = delete;
/* static Singleton* pInstance; */
static unique_ptr<Singleton> pInstance;
static mutex mtx; //互斥锁,确保线程安全
};
/* Singleton* Singleton::pInstance = nullptr; */
unique_ptr<Singleton> Singleton::pInstance = nullptr;
mutex Singleton::mtx;
int main()
{
Singleton* s1 = Singleton::getInstance();
Singleton* s2 = Singleton::getInstance();
if(s1 == s2){
cout << "s1 == s2,是单例的\n";
}else{
cout << "s1 != s2,不是单例的\n";
}
return 0;
}
6.饿汉式
饿汉式:在类加载时就进行实例化
cpp
#include <iostream>
using namespace std;
class Singleton{
public:
// 提供全局访问点
static Singleton& getInstance()
{
// 静态局部变量在程序启动时初始化
static Singleton instance;
return instance;
}
// 删除拷贝构造函数和赋值操作符,防止复制
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
// 示例方法
void display() const{
cout << "Singleton::display() called on instance: " << this << endl;
}
private:
// 私有构造函数
Singleton(){
cout << "Singleton()" << endl;
}
// 私有析构函数
~Singleton(){
cout << "~Singleton()" << endl;
}
};
int main()
{
// 通过getInstance获取单例对象的引用,并调用示例方法
Singleton& s1 = Singleton::getInstance();
s1.display();
// 再次获取单例对象的引用,验证它们是同一个实例
Singleton& s2 = Singleton::getInstance();
s2.display();
// 输出将展示s1和s2有相同的地址,说明它们是同一个实例
return 0;
}