单例模式保证一个类仅有一个实例,并提供一个访问它的全局访问点,其类图如下图所示: 在《设计模式 可服用面向对象软件的基础》一书中给出过C++中实现单例模式的经典实现,但书中给出的实现有着下面的不足:
- 未使用模版技术,无法将单例模式类与具体类分离,从而无法方便的将任何类设置为单例类
- 未使用智能指针技术,需要手动释放内存
而本文的代码的实现中则通过C++11的以下机制克服了上面的缺点:
- 使用可变参数模版技术,使得单例模式支持任意参数的构造函数
- 使用类模板技术,支持以非继承的方式将任意类转为“单例类”
- 使用智能指针技术,无需担心单例对象内存的释放
- 也支持通过继承的方式,使得子类为单例类
下面代码的实现参考《深入应用C++11 代码优化与工程级应用》
//
// MySingleton.h
// Created by Yyh on 2022/3/13.
#ifndef _MySingleton_h_
#define _MySingleton_h_
#include <memory>
template <typename T>
class MySingleton
{
public:
//初始化单例
template<typename ... Args>
static std::shared_ptr<T> Instance(Args &&... args)
{
m_pInstance = std::make_shared<T>(std::forward<Args>(args)...); //完美转发
return m_pInstance;
}
//获取单例
static std::shared_ptr<T> GetInstance()
{
if(m_pInstance == nullptr)
{
//如果未初始化的前提下获取单例则抛出异常
throw std::logic_error("the instance is not init, please initialize the instance first");
}
return m_pInstance;
}
protected:
virtual ~MySingleton(){}
MySingleton(){}
private:
static std::shared_ptr<T> m_pInstance;
};
template <class T>
std::shared_ptr<T> MySingleton<T>::m_pInstance = nullptr;
#endif
下面是测试函数:
#include <iostream>
#include "MySingleton.h"
using namespace std;
struct A
{
A()
{
strText = "A()";
}
std::string strText;
};
struct B
{
B(std::string strParam)
{
strText = std::string("B(") + strParam + ")";
}
std::string strText;
};
struct C : public MySingleton<C>
{
std::string strText;
C(std::string strParam)
{
strText = std::string("C(") + strParam + ")";
}
};
int main(int argc, char *argv[]) {
MySingleton<A>::Instance();
MySingleton<B>::Instance("b");
C::Instance("c");
cout << "A:" << MySingleton<A>::GetInstance()->strText << endl;
cout << "B:" << MySingleton<B>::GetInstance()->strText << endl;
cout << "C:" << C::GetInstance()->strText << endl;
}
参考:
- 《深入应用C++11 代码优化与工程级应用》
- 《设计模式 可服用面向对象软件的基础》