C++ 单例模式智能指针实现

本文介绍了一种使用智能指针实现的C++单例模式,通过私有构造函数和静态成员函数确保类的唯一实例,并在实例创建时加锁避免多线程环境下可能的问题。

在前端或者后台开发过程中,或多或少都要有一些全局变量,或者某个关键数据不允许重复构造,这个时候单例模式在C++程序中是一个不错的选择。
本代码示例结合智能指针做了一个单例模式。

class IwmGlobal : private std::enable_shared_from_this<IwmGlobal>
{
public:
	IwmGlobal(const IwmGlobal &) = delete;
	IwmGlobal &operator=(const IwmGlobal &) = delete;

	static std::shared_ptr<IwmGlobal> &instance() {
		if (nullptr != s_instance)
		{
			return s_instance;
		}

		Mutex::Locker lock(s_mutex);
		if (nullptr != s_instance)
		{
			return s_instance;
		}
		s_instance = shared_ptr<IwmGlobal>(new IwmGlobal());
		return s_instance;
	}
private:
	static std::shared_ptr<IwmGlobal>  s_instance;
	IwmGlobal() { m_bInit = FALSE; }
	static Mutex s_mutex;

private:
	BOOL m_bInit;

public:
	//所有配置文件相关信息
	std::shared_ptr<ConfigData>  appCfg;
	IchsPool<IWMBaseMsgPtr>      taskManMsgQueue;
	IchsPool<IWMBaseMsgPtr>      robotCtrlQueue;
	std::shared_ptr<crMioEx>     mqHandle;

	string listener_topic;
};
typedef std::shared_ptr<IwmGlobal> IwmGlobalPtr;

说明:
1、将构造函数声明为 private

 private:
	static std::shared_ptr<IwmGlobal>  s_instance;
	IwmGlobal() { m_bInit = FALSE; }

2、将C++类的默认实现的类重载函数去掉

    IwmGlobal(const IwmGlobal &) = delete;
	IwmGlobal &operator=(const IwmGlobal &) = delete;

3、初始化实例

static std::shared_ptr<IwmGlobal> &instance() {
		if (nullptr != s_instance)
		{
			return s_instance;
		}

		Mutex::Locker lock(s_mutex);
		if (nullptr != s_instance)
		{
			return s_instance;
		}
		s_instance = shared_ptr<IwmGlobal>(new IwmGlobal());
		return s_instance;
	}

因为单例模式无法直接调用make_shared()进行实例化,原因是构造函数为private,无法被外部调用,所以折中的方式是:

s_instance = shared_ptr<IwmGlobal>(new IwmGlobal());

注意:
因为是单例模式,相当于全局变量的存在,在程序加载过程中可能会存在instance多线程同时加载的情况, 为了避免该懒加载模式出现问题,最好加一个资源锁。
另外,单例模式设计过程需要明确区分,句柄初始化和数据加载初始化。
1、句柄初始化
句柄初始化为类或者结构体初始化,
2、数据加载初始化
而数据加载初始化是为了服务正常工作,需要加载配置数据或者连接初始化(如服务配置、tcp连接、服务初始化、db数据库连接初始化、MQ连接初始化、redis连接初始化)

个人理解,单例模式适合做句柄初始化,从程序架构上来看,最好将逻辑分开,一则污染了单例模式的设计本意,二则代码逻辑上对单例模式也是承重的负担。数据加载初始化建议采用工厂模式解耦处理。

### 使用智能指针实现C++中的单例模式 在现代C++中,`std::unique_ptr` 和 `std::shared_ptr` 是两种常用的智能指针类型。对于单例模式而言,通常推荐使用 `std::unique_ptr` 来管理实对象的生命期,因为这可以确保只有一个所有者,并且避免不必要的引用计数开销。 下面是一个基于 `std::call_once` 和 `std::unique_ptr` 的线程安全的懒加载类模板实现: ```cpp #include <memory> #include <mutex> template<typename T> class Singleton { private: static std::unique_ptr<T> instance; static std::once_flag initFlag; protected: // Allow derived classes to construct instances. Singleton() = default; public: ~Singleton() = default; // Delete copy constructor and assignment operator. Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; // Get the single instance of this class. static T* getInstance() { std::call_once(initFlag, [](){ instance.reset(new T()); }); return instance.get(); } }; // Initialize static members outside the class definition. template<typename T> std::unique_ptr<T> Singleton<T>::instance(nullptr); template<typename T> std::once_flag Singleton<T>::initFlag; ``` 此代码片段展示了如何利用 C++11 特性来创建一个既简又高效的单例模式[^2]。通过这种方式定义的不仅能够保证多线程环境下的安全性,同时也遵循了良好的资源管理和内存释放原则。 #### 关键点解释 - **静态成员变量初始化**:为了使编译器能够在程序启动前完成必要的准备工作,需要在外部分别声明并初始化两个静态数据成员。 - **删除拷贝语义**:为了避免意外复制或赋值操作破坏性质,在类内部显式禁用了这两个特殊函数。 - **延迟初始化机制**:借助于标准库提供的 `std::call_once()` 函数以及相应的标志位 (`std::once_flag`) ,可以在首次调用 `getInstance()` 方法时才真正构建唯一的实对象。 - **自动销毁**:当全局作用域结束时(即应用程序终止),由 `std::unique_ptr` 自动负责清理所持有的资源。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值