实现一个模板形式的单例类,对于任意类型的类经过Singleton的处理之后,都能获取一个单例对象,并且可以传递任意参数
并且还使用了智能指针,把生成的单例对象托管给智能指针,从而实现自动回收单例对象的资源
此外,如果需要一个放在静态成员区的对象供其他类使用,又不希望修改原有的类的代码,这时候可以通过该模板套一层壳,形成单例对象。
头文件
template_singleton.hpp
#include <iostream>
#include <string>
#include <memory>
using std::cout;
using std::endl;
using std::string;
using std::shared_ptr;
using std::make_shared;
template <typename T> class Singleton;
class Point
{
//由于构造和析构被设为私有,想使用单例模板创造对象,就应该把其设为友元
template <typename T> friend class Singleton;
public:
//把析构函数设为private之后,智能指针销毁时无法调用
//所以析构应该设置为public,但是就算是共有的析构,由于是把单例对象的内容托管给了智能指针
//通过智能指针显式的调用析构函数,也是无法回收单例对象的,所以,不影响单例模式的实现
~Point(){
cout << "~Point()" << endl;
}
void show(){
cout << "(" << _ix << ", " << _iy << ")" << endl;
}
private:
//单例模式,要把构造函数和析构函数设为私有
Point(int x, int y) : _ix(x), _iy(y)
{
cout << "Point(int, int)" << endl;
}
/* ~Point(){ */
/* cout << "~Point()" << endl; */
/* } */
private:
int _ix;
int _iy;
};
class Computer
{
//由于构造和析构被设为私有,想使用单例模板创造对象,就应该把其设为友元
template <typename T> friend class Singleton;
public:
void show(){
cout << "name: " << _name << " price: " << _price << endl;
}
void reset(const string &newname, const int &newprice){
_name = newname;
_price = newprice;
}
//使用public的析构函数,不影响单例模式的实现
~Computer(){
cout << "~Computer()" << endl;
}
private:
//单例模式,要把构造函数设为私有
//使用模板生成单例对象的时候调用了make_shared函数,如果传入的是栈上的内容
//make_shared函数会调用拷贝构造函数在堆上重新生成一个托管给智能指针的对象,
//并把原先的对象销毁,所以会在make_shared里面执行一次析构函数
/* Computer(const Computer &rhs){ */
/* cout << "拷贝构造函数" << endl; */
/* } */
Computer(const string &name, const int price)
:_name(name), _price(price)
{
cout << "Computer(const string &, const int &)" << endl;
}
/* ~Computer(){ */
/* cout << "~Computer()" << endl; */
/* } */
private:
string _name;
int _price;
};
//模板形式的单例类(使用了智能指针),应该使用饱汉模式
template <typename T>
class Singleton
{
public:
template <typename ...Args>
static shared_ptr<T> getInstance(Args... args){
if(_pInstance == nullptr){
//这里会直接调用相应的类型的构造函数,托管给智能指针,类型在实例化后确定
/* //使用临时对象托管给智能指针的时候,由于临时对象分配在栈上, */
/* //所以在make_shared内部会重新分配堆上的空间来保存其内容, */
/* //会调用拷贝构造函数,并把临时对象销毁 */
/* _pInstance = make_shared<T>(T(args...)); */
//如果把一个分配在堆上的指针托管给智能指针,传入的指针就不会被销毁
T *tmp = new T(args...);
_pInstance = make_shared<T>(*tmp);
}
return _pInstance;
}
private:
//由于使用了模板,所以_pInstance实际上指向的是 T ,而非本类型,
//所以并不会生成Singleton对象,而是直接生成相应的T对象
//T在实例化之后才会确定,究竟是哪种类型,
//所以Singleton的构造函数和析构函数并不会执行
Singleton(){
cout << "Singleton()" << endl;
}
~Singleton(){
cout << "~Singleton()" << endl;
}
static shared_ptr<T> _pInstance; //单例模式的指针,指向唯一的实体
};
//由于类型在实例化是才会确定,所以使用饱汉模式
template <typename T>
shared_ptr<T> Singleton<T>::_pInstance = nullptr;
|
测试文件
test_template_singleton.cc
#include "template_singleton.hpp"
#include <stdio.h>
using std::cout;
using std::endl;
using std::cin;
void test(){
shared_ptr<Computer> pc1 = Singleton<Computer>::getInstance("Xiaomi", 6666);
cout << "pc1: ";
pc1->show();
shared_ptr<Computer> pc2 = Singleton<Computer>::getInstance("Xiaomi", 6666);
cout << "pc1: ";
pc1->show();
cout << "pc2: ";
pc2->show();
pc2->reset("Huawei", 8888);
cout << endl << "after pc2->reset()" << endl;
cout << "pc1: ";
pc1->show();
cout << "pc2: ";
pc2->show();
cout << endl;
shared_ptr<Point> pt3 = Singleton<Point>::getInstance(1, 2);
shared_ptr<Point> pt4 = Singleton<Point>::getInstance(1, 2);
cout << endl << "通过模板,可以生成不同类型的单例对象:" << endl;
cout << "pt3: ";
pt3->show();
cout << "pt4: ";
pt4->show();
cout << endl << "使用了智能指针,不同对象指向的地址也一样:" << endl;
printf("&pc1 = %p\n", &pc1);
printf("&pc2 = %p\n", &pc2);
printf("&pt3 = %p\n", &pt3);
printf("&pt4 = %p\n\n", &pt4);
printf("&(*pc1) = %p\n", &(*pc1));
printf("&(*pc2) = %p\n", &(*pc2));
printf("&(*pt3) = %p\n", &(*pt3));
printf("&(*pt4) = %p\n\n", &(*pt4));
}
int main()
{
test();
return 0;
}
|
运行结果
Computer(const string &, const int &)
pc1: name: Xiaomi price: 6666
pc1: name: Xiaomi price: 6666
pc2: name: Xiaomi price: 6666
after pc2->reset()
pc1: name: Huawei price: 8888
pc2: name: Huawei price: 8888
Point(int, int)
# 通过模板,可以生成不同类型的单例对象:
pt3: (1, 2)
pt4: (1, 2)
# 使用了智能指针,不同对象指向的地址也一样:
&pc1 = 0x7ffe83bbd390
&pc2 = 0x7ffe83bbd3a0
&pt3 = 0x7ffe83bbd3b0
&pt4 = 0x7ffe83bbd3c0
&(*pc1) = 0x55b750c7e300
&(*pc2) = 0x55b750c7e300
&(*pt3) = 0x55b750c7e360
&(*pt4) = 0x55b750c7e360
~Point()
~Computer()
|
|