C++单例模式模板类

        在C++的代码中是要尽量避免使用全局变量的,全局变量可能在程序的任一地方被修改,提高代码的定位难度,还会导致代码耦合性变高,难以模块化测试。但有时候一个类对象想要全局使用,且全局只能初始化一次,这时就可以引入单例模式的思想。这里提到的只是单例模式应用的一个场景,实际上全局变量和单例没太大的相关性,单例和静态类的区别在这里不再赘述,网上可以查找到相关的对比,比如下面这个是C#上的说明:

单例模式和静态类 - kerwin cui - 博客园

一、单例模式

        在《Head First 设计模式》一书中,单例模式的定义是“确保一个类只有一个实例,并提供一个全局访问点”,类图如下:

        通过类图可以看到单例类有两个明显的特点:① 构造函数是私有的,这样在类外就不能随意进行实例化;② 有一个静态的函数,用来获取类内实例化的对象,类的静态函数可以在代码的任何地方进行调用。根据单例类的这两个特点,可以设计出两种经典的单例模式:懒汉式和饿汉式,还有基于懒汉式的线程安全的双检测锁模式,在下面这篇文章中有很详细的说明:

C++ 单例模式 - 知乎

二、双检测锁模式

        为了在多线程下使用单例模式,基于线程安全问题仅出现在第一次初始化(new)过程中,引入了双检锁模式。第一次检测不涉及到对象的创建,因此是不加锁的检测,不需要锁的时间消耗,只有检测到对象暂未创建的时候,才会进行对象的加锁操作,然后再进行数据的第二次检测,避免在加锁期间,对象已经创建成功,只有二次检测到对象尚未创建才会创建唯一的实例。

        为了在大规模的代码中,方便多个类都定义为单例类,且在写类的代码时不需要太大变动且模式统一,因此本文定义了一个模板类,通过可变模板参数和友元函数的概念,实现调用的统一,具体实现代码如下:

template <typename T>
class Singleton {
public:
	template<typename... Args>
	static inline std::shared_ptr<T> instance(Args&& ... args) {
		// 双检测锁模式
		if (!instance_.get()) {
			std::unique_lock<std::mutex> lock(instanceMutex_);
			if (!instance_.get()) {
				instance_.reset(new T(std::forward<Args>(args)...));
			}
		}
		return instance_;
	}

private:
	Singleton() = default;
	virtual ~Singleton() = default;
	Singleton(const Singleton&) = default;
	Singleton& operator = (const Singleton&) = delete;

	// 实例
	static std::shared_ptr<T> instance_;
	static std::mutex instanceMutex_;
};

template <typename T>
std::shared_ptr<T> Singleton<T>::instance_;

template <typename T>
std::mutex Singleton<T>::instanceMutex_;

#define SINGLETON_DECL(type) \
    friend class std::shared_ptr< type >; \
    friend class Singleton< type >;

        双检锁模式可以在多线程下保证线程的安全,但并不是绝对的。某些内存模型、编译器的优化或者运行时优化等情况下,会先分配完内存再进行数据的构造,造成另一个线程如果调用getInstance()获取到一个不完全初始化的对象,从而出现崩溃的情况。这种情况一个是通过内存屏障(memory barrier)的方式解决,一个是在主函数或者是比较早期的时候就完成单例的创建,还有一个方式是atomic实现,可以参考第一节中《C++ 单例模式》链接里面讲解的很清晰,这里不再赘述,只提供一种单例模板类的实现思路。

三、单例模板类的调用

        将单例模板类定义在头文件Singleton.h中,其它头文件中想要定义为单例模式的类,只需要对其进行引用(#include Singleton.h)即可进行使用,假设我们想定义一个单例类A,则可以通过以下代码实现:

class A{
private:
    A() {}
	
public:
    ~A() {}
    
    int funA() {}
	
private:
    SINGLETON_DECL(A);
};


// 调用单例类A的公共成员函数
Singleton<A>::instance()->funA();
// 在调用的时候会进行实例是否已创建的检查

        可以看到调用是比较简单且统一的,不需要针对每个类再单独写双检测锁的部分。单例模式的实现方式有很多,可以根据项目实际需求选择具体方式,不管是懒汉式、饿汉式还是优化实现,都可以通过可变参数模板进行全局的统一管理。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
单例模式是一种创建对象的设计模式,它保证一个类只有一个实例,并提供一个全局访问点。 下面是一个简单的C++单例模式模板示例: ```cpp #include <iostream> template<typename T> class Singleton { public: // 获取单例实例 static T& getInstance() { static T instance; return instance; } // 防止拷贝构造和赋值操作 Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; private: // 构造函数私有化 Singleton() { std::cout << "Singleton instance created." << std::endl; } ~Singleton() { std::cout << "Singleton instance destroyed." << std::endl; } }; class MyClass { public: void print() { std::cout << "Hello, World!" << std::endl; } }; int main() { // 获取MyClass的单例实例 MyClass& instance = Singleton<MyClass>::getInstance(); // 使用单例实例 instance.print(); return 0; } ``` 在上述示例中,`Singleton`是一个通用的单例模板类,通过调用`getInstance`方法可以获取该类的单例实例。构造函数和析构函数私有化,防止外部直接创建和销毁对象。此外,为了防止拷贝构造和赋值操作,使用了`delete`关键字禁用了这两个函数。 `MyClass`是一个示例类,通过单例模式创建其单例对象,并调用对象的`print`方法。 运行该程序,可以看到输出结果为“Singleton instance created.”和“Hello, World!”。使用单例模式创建的对象只有一个实例,即使多次调用`getInstance`方法,返回的也是同一个实例。 总之,单例模式模板可以通过模板类和静态方法实现一个类的单例实例,避免了多次创建和销毁对象,同时提供了全局访问点,方便对象的使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值