C++单例设计模式

单例模式

单例模式设计的类只能实例化一个对象,但是这个对象可以在全局使用。实现方法:类自身保存自己的实例,提供访问该实例的方法。
在这里插入图片描述

实现方法

  1. 声明自己的静态私有对象
  2. 将创造对象的构造函数设置为私有,那么外界就无法创建对象了
  3. 提供公有的访问对象的静态函数

预备知识:静态成员和静态变量:

  1. 将成员或函数声明为静态的,那么这些成员和变量在类的所有对象之间是共享的,相当于类内全局变量。其中一个用途用来记录该类实例了多少对象。
  2. 静态成员函数是没有this指针的,C++中调用方式 <类名>::<成员>
  3. 一般类在实例化对象的时候会为类成员分配内存空间。但是静态成员函数和静态成员变量在实例化对象的时候不会被分配内存空间,因为在对象创建之前(编译阶段)就已经被分配了内存。
  4. 静态成员变量不能在类内初始化,这样可以防止每个对象都包含静态成员

预备知识:互斥锁

  1. 头文件#include《mutex》
  2. 实例化:std::mutex mtx
  3. 上锁:mtx.lock(), mtx.try_lock();解锁mtx.unlock()

单线程单例模式

#include<iostream>

//单例模式类的定义
class Singleton {
private:
	Singleton() {};
	~Singleton() {};
public:
	static Singleton* GetSingletonObject() {  //提供单例的访问接口
		if (singleton_object == nullptr) {         //第一次调用时,分配内存空间
			singleton_object = new Singleton();
		}
		return singleton_object;
	}
private:
	//static Singleton *singleton_object  = nullptr;     //错误,静态成员变量不能在类内初始化
	static Singleton *singleton_object;           //静态成员变量,就是单例模式中共享的实例
};


/**********************************客户端调用,用于验证*****************************/
Singleton* Singleton::singleton_object = nullptr; //在类外初始化静态成员变量
int main() {
	Singleton *s1 = Singleton::GetSingletonObject();
	Singleton *s2 = Singleton::GetSingletonObject();
	if (s1 == s2) {
		std::cout << "是同一个对象" << std::endl;
	}
	return 0;
}

由于没有释放类成员singleton_object的内存,会造成内存泄露,下面博客提出了解决办法:
C++中的单例模式
其中的《effective C++》实现的方式中,local static实现方式是指: 将每个 non-local static对象搬到自己的专属函数内,这些函数返回一个reference指向它所指向的对象。这个手法的基础在于:C++保证,在“该函数被调用期间”“首次遇到该对象”时进行初始化。

多线程单例模式
上述单线程单例模式在多个线程同时检测到singleton_object == nullptr时,会创建多个single_object;所以需要进行上锁

public:
	static Singleton* GetSingletonObject() {  //提供单例的访问接口
		mtx.lock();
		if (singleton_object == nullptr) {         //第一次调用时,分配内存空间
			singleton_object = new Singleton();
		}
		mtx.unlock();
		return singleton_object;
	}

这里每次运行GetSingletonObject的时候都要进行互斥锁的操作,很影响效率。所以人们发明了双锁,

public:
	static Singleton* GetSingletonObject() {  //提供单例的访问接口
		if (singleton_object == nullptr) {
			mtx.lock();
			if (singleton_object == nullptr) {         //第一次调用时,分配内存空间
				singleton_object = new Singleton();
			}
			mtx.unlock();
		}
		return singleton_object;
	}

参考博客:C++程序员们,快来写最简洁的单例模式吧
参考书籍《大话设计模式》
参考博客:C++11并发指南三(std::mutex详解)

### C++ 中的单例设计模式实现 #### 实现方式一:懒汉式(Lazy Initialization) 懒汉式的单例模式会在第一次调用 `getInstance` 方法时创建实例。 ```cpp class Singleton { public: static Singleton* getInstance() { if (instance == nullptr) { instance = new Singleton(); } return instance; } private: Singleton() {} static Singleton* instance; }; Singleton* Singleton::instance = nullptr; ``` 这种方式简单易懂,但在多线程环境下可能会出现问题[^1]。 #### 实现方式二:饿汉式(Eager Initialization) 饿汉式的单例模式在类加载时就创建好实例,避免了懒汉式中可能出现的线程安全问题。 ```cpp class Singleton { public: static Singleton& getInstance() { static Singleton instance; return instance; } private: Singleton() {} }; ``` 这种方法利用了局部静态变量的特点,在首次访问时初始化对象,并且是线程安全的。 #### 实现方式三:双重检查锁定(Double-Checked Locking) 为了提高性能并保持线程安全性,可以采用双重检查锁定机制来优化懒汉式实现: ```cpp #include <mutex> class Singleton { public: static Singleton* getInstance() { if (instance == nullptr) { // First check before locking std::lock_guard<std::mutex> lock(mutex_); if (instance == nullptr) { // Second check after acquiring the lock instance = new Singleton(); } } return instance; } private: Singleton() {} static Singleton* instance; static std::mutex mutex_; }; Singleton* Singleton::instance = nullptr; std::mutex Singleton::mutex_; ``` 此方法减少了不必要的同步开销,适用于高并发场景下的单例管理。 #### 防止克隆破坏单例特性 为了避免通过复制构造函数或赋值操作符意外地创建新的实例,应该禁用这些功能: ```cpp class Singleton { public: static Singleton& getInstance(); protected: Singleton() {}; private: Singleton(const Singleton&) = delete; // Prevent copy construction Singleton& operator=(const Singleton&) = delete; // Prevent assignment ~Singleton() {}; // Destructor should also be protected/private }; ``` 上述措施确保了即使有人尝试拷贝现有实例也不会成功,从而维护了单例性质[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值