前言
本文是记录个人对c++11读写相关的学习,文中所用可能会采用其他大神的图、思路、例子等,请大神们见谅。本博客文章是在学习过程的一些总结,整理出来,分享给大家,希望对各位读者有帮助,文章中的总结可能存在很多不完整或有错误的地方,也希望读者指出。
1、改进单例模式
通过创建单例的模板函数来实现
template <typename T>
class Singleton
{
public:
//支持0个参数的构造函数
static T* Instance()
{
if(m_pInstance == nullptr)
m_pInstance = new T();
printf("0pram contruct\n");
return m_pInstance;
}
//支持1个参数的构造函数
template <typename T0>
static T* Instance(T0 arg0)
{
if(m_pInstance == nullptr)
m_pInstance = new T(arg0);
printf("1pram contruct\n");
return m_pInstance;
}
//支持2个参数的构造函数
template <typename T0, typename T1>
static T* Instance(T0 arg0, T1 arg1)
{
if(m_pInstance == nullptr)
m_pInstance = new T(arg0, arg1);
printf("2pram contruct\n");
return m_pInstance;
}
template <typename T0, typename T1, typename T2>
static T* Instance(T0 arg0, T1 arg1, T2 arg2)
{
if(m_pInstance == nullptr)
m_pInstance = new T(arg0, arg1, arg2);
return m_pInstance;
}
//获取单例
static T* GetInstance()
{
if(m_pInstance == nullptr)
throw std::logic_error("the instance is not init, please initialize the instance first");
return m_pInstance;
}
//释放单例
static void DestroyInstance()
{
delete m_pInstance;
m_pInstance = nullptr;
}
private:
//不允许复制和赋值
Singleton(void);
virtual ~Singleton(void);
Singleton(const Singleton&);
Singleton& operator = (const Singleton&);
private:
static T* m_pInstance;
};
template <class T> T* Singleton<T>::m_pInstance = nullptr;
struct A
{
A(){}
};
struct B
{
B(int x){}
};
struct C
{
C(int x, double y){}
};
int main()
{
Singleton<A>::Instance();
Singleton<B>::Instance(1);
Singleton<C>::Instance(1, 3.14);
Singleton<A>::DestroyInstance();
Singleton<B>::DestroyInstance();
Singleton<C>::DestroyInstance();
}
总结:可以看出有着很多重复的模板定义,而且随着参数的增多,模板个数也不不断增多,不灵活且不简洁
template <typename T>
class Singleton
{
public:
template<typename... Args>
static T* Instance(Args&&... args){
if(m_pInstance == nullptr)
m_pInstance = new T(std::forward<Args>(args)...); //完美转发
return m_pInstance;
}
//获取单例
static T* GetInstance()
{
if(m_pInstance == nullptr)
throw std::logic_error("the instance is not init, please initialize the instance first");
return m_pInstance;
}
//释放单例
static void DestroyInstance()
{
delete m_pInstance;
m_pInstance = nullptr;
}
private:
//不允许复制和赋值
Singleton(void);
virtual ~Singleton(void);
Singleton(const Singleton&);
Singleton& operator = (const Singleton&);
private:
static T* m_pInstance;
};
template <class T> T* Singleton<T>::m_pInstance = nullptr;
struct A
{
A(const string&){cout<<"lvaue"<<endl;}
A(string&& x){cout<<"rvaue"<<endl;}
};
struct B
{
B(const string&){cout<<"lvaue"<<endl;}
B(string&& x){cout<<"rvaue"<<endl;}
};
struct C
{
C(int x, double y){}
void Fun(){cout<<"test"<<endl;}
};
int main()
{
string str = "bb";
Singleton<A>::Instance(str); //创建A类型的单例
Singleton<B>::Instance(std::move(str));//创建B类型的单例,临时变量str被move之后变成了右值,然后才可以根据移动语义来避免复制
Singleton<C>::Instance(1, 3.14);
Singleton<C>::GetInstance()->Fun();
Singleton<A>::DestroyInstance();
Singleton<B>::DestroyInstance();
Singleton<C>::DestroyInstance();
}
总结:没有重复的模板的定义,支持任意个参数类型的创建,支持完美转发。能够将左值或者右值转发到对应的构造函数种,通过右值引用的移动还能进一步提升性能
2、改进观察者模式
1)简单的观察者模式实现
Observer.h
class Observer
{
public:
Observer() {};
virtual ~Observer() {};
// 定义纯虚函数,规范接口
virtual void update() = 0;
};
Subject.h
#include <vector>
using namespace std;
class Observer;
class Subject
{
public:
Subject() {};
virtual ~Subject() {};
void addObserver(Observer *observer);
void deleteObserver(Observer *observer);
void notifyObservers();
virtual int getStatus() = 0;
virtual void setStatus(int status) = 0;
private:
std::vector<Observer*> m_observers;
};
Subject.cpp
#include "Subject.h"
#include "Observer.h"
void Subject::addObserver(Observer *observer)
{
m_observers.push_back(observer);
}
void Subject::deleteObserver(Observer * observer)
{
for (vector<Observer*>::iterator iter = m_observers.begin();
iter != m_observers.end(); iter++)
{
if (*iter == observer)
{
m_observers.erase(iter);
return;
}
}
}
void Subject::notifyObservers() {
for (vector<Observer*>::iterator iter = m_observers.begin();
iter != m_observers.end();
iter++)
{
(*iter)->update();
}
}
ConcreteSubject.h
#include <string>
#include "Subject.h"
using namespace std;
class ConcreteSubject : public Subject
{
public:
ConcreteSubject(string name) :m_subjectName(name) {};
~ConcreteSubject() {};
void setStatus(int status);
int getStatus();
private:
string m_subjectName;
int m_status = 0;
};
ConcreteSubject.cpp
#include <iostream>
#include "ConcreteSubject.h"
using namespace std;
void ConcreteSubject::setStatus(int status)
{
m_status = status;
cout << "setStatus subject[" << m_subjectName << "] status:" << status << endl;
}
int ConcreteSubject::getStatus()
{
return m_status;
}
ConcreteObserver.h
#include <string>
#include "Observer.h"
class Subject;
using namespace std;
class ConcreteObserver:public Observer
{
public:
ConcreteObserver(string name, Subject *subject) :m_observerName(name), m_subject(subject) {};
~ConcreteObserver() {};
void update();
private:
string m_observerName;
Subject *m_subject;
};
ConcreteObserver.cpp
#include <iostream>
#include "ConcreteObserver.h"
#include "Subject.h"
using namespace std;
void ConcreteObserver::update()
{
cout << "update observer[" << m_observerName << "] status:" << m_subject->getStatus() << endl;
}
main.cpp
#include <iostream>
#include "ConcreteObserver.h"
#include "ConcreteSubject.h"
int main(int argc, char *argv[])
{
Subject * subjectA = new ConcreteSubject("subjectA");
Subject * subjectB = new ConcreteSubject("subjectB");
Observer * observerA = new ConcreteObserver("observerA", subjectA);
Observer * observerB = new ConcreteObserver("observerB", subjectB);
subjectA->addObserver(observerA);
subjectB->addObserver(observerB);
subjectA->setStatus(1);
subjectA->notifyObservers();
subjectB->setStatus(2);
subjectB->notifyObservers();
cout << "--------------------" << endl;
subjectA->addObserver(observerB);
subjectA->setStatus(2);
subjectA->notifyObservers();
delete subjectA;
delete subjectB;
delete observerA;
delete observerB;
return 0;
}
makefile
# 方便起见一般都会先定义编译器链接器
CC = g++
LD = g++
# 正则表达式表示目录下所有.c文件,相当于:SRCS = main.c a.c b.c
SRCS = $(wildcard *.cpp)
# OBJS表示SRCS中把列表中的.c全部替换为.o,相当于:OBJS = main.o a.o b.o
OBJS = $(patsubst %cpp, %o, $(SRCS))
# 可执行文件的名字
TARGET = test1
# .PHONE伪目标,具体含义百度一下一大堆介绍
.PHONY:all clean
# 要生成的目标文件
all: $(TARGET)
# 第一行依赖关系:冒号后面为依赖的文件,相当于Hello: main.o a.o b.o
# 第二行规则:$@表示目标文件,$^表示所有依赖文件,$<表示第一个依赖文件
$(TARGET): $(OBJS)
$(LD) -o $@ $^
# 上一句目标文件依赖一大堆.o文件,这句表示所有.o都由相应名字的.c文件自动生成
%.o:%.c
$(CC) -c $^
# make clean删除所有.o和目标文件
clean:
rm -f $(OBJS) $(TARGET)
总结如下:
1)实现不够通用,只能对特定观察者才能有效(只能对observer抽象类的派生类才能生效,且不能带参数)
2)需要继承,强对象关系,不够灵活
3)观察者被通知的接口参数不支持变化,导致观察者不能应付接口的变化
2)改进的观察者模式
1)通过该被通知接口参数化和std::function代替继承
2)通过可变参数模板和完美转发消除接口变化的影响
3)方便增加或者移除观察者
4)将类设置不可复制
class NonCopyable
{
protected:
NonCopyable() = default;
~NonCopyable() = default;
NonCopyable(const NonCopyable&) = delete; //禁止复制构造
NonCopyable & operator = (const NonCopyable&) = delete; //禁止赋值构造
};
#include <iostream>
#include <string>
#include <functional>
#include <map>
using namespace std;
template<typename Func>
class Events : NonCopyable
{
public:
Events(){}
~Events(){}
int Connect(Func&& f){ //注册观察者,支持右值引用
return Assgin(f);
}
int Connect(const Func& f){ //注册观察者
return Assgin(f);
}
void Disconnect(int key){
m_connections.erase(key);
}
//通知所有的观察者
template<typename... Args>
void Notify(Args&&... args){
for(auto& it:m_connections){
it.second(std::forward<Args>(args)...);
}
}
private:
template<typename F> //保存观察者并分配观察者的编号
int Assgin(F&& f){
int k = m_observerId++;
m_connections.emplace(k, std::forward<F>(f));
return k;
}
int m_observerId = 0; //观察者对应的编号
std::map<int, Func> m_connections; //观察者列表
};
struct stA
{
int a, b;
void print(int a, int b){
cout <<"stA:" << a <<","<<b << endl;
}
};
void print(int a, int b){
cout << a <<","<<b << endl;
}
int main(){
Events<std::function<void(int, int)>> myevent;
auto key = myevent.Connect(print); //以函数方式注册观察者
stA t;
auto lambdakey = myevent.Connect([&t](int a, int b){t.a = a; t.b = b;});//lambda注册
std::function<void(int, int)> f = std::bind(&stA::print, &t, std::placeholders::_1, std::placeholders::_2);// std::function注册
myevent.Connect(f);
int a=1,b=2;
myevent.Notify(a, b); //广播所有观察者
myevent.Disconnect(key); //移除观察者
return 0;
}
总结:
类内部维护了一个泛型函数列表,观察者只需要将观察者函数注册进来即可,消除了继承引起的强耦合;通过接口使用了可变参数模块,支持任意参数,消除了接口变化
3、访问者模式
#include <iostream>
using namespace std;
//没使用访问者模式
namespace unVisit {
//foo1和foo2是原有接口,但是现在要新增foo3。
class Composite {
public:
virtual void foo1() = 0;
virtual void foo2() = 0;
virtual void foo3() = 0; //新增代码
};
class Composite1 : public Composite {
public:
void foo1() override {
cout << __PRETTY_FUNCTION__ << endl;
}
void foo2() override {
cout << __PRETTY_FUNCTION__ << endl;
}
//新增代码
void foo3() override {
cout << "新增函数" << endl;
}
};
class Composite2 : public Composite {
public:
void foo1() override {
cout << __PRETTY_FUNCTION__ << endl;
}
void foo2() override {
cout << __PRETTY_FUNCTION__ << endl;
}
//新增代码
void foo3() override {
cout << "新增函数" << endl;
}
};
}
namespace Visit {
class Composite;
class Composite1;
class Composite2;
//非仿函数版本
class Visit {
public:
virtual void composite1(Composite &composite) = 0;
virtual void composite2(Composite &composite) = 0;
};
//仿函数
class Foo {
public:
virtual void operator()(Composite1 &composite1) = 0;
virtual void operator()(Composite2 &composite1) = 0;
};
class Composite {
public:
virtual void foo1() = 0;
virtual void foo2() = 0;
//预留接口(非仿函数版本)
virtual void futureFoo(Visit &visit) = 0;
//仿函数版本
virtual void operatorFoo(Foo &foo) = 0;
};
class Composite1 : public Composite {
public:
void foo1() override {
cout << __PRETTY_FUNCTION__ << endl;
}
void foo2() override {
cout << __PRETTY_FUNCTION__ << endl;
}
void futureFoo(Visit &visit) override {
visit.composite1(*this);
}
void operatorFoo(Foo &foo) override {
foo.operator()(*this);
}
};
class Composite2 : public Composite {
public:
void foo1() override {
cout << __PRETTY_FUNCTION__ << endl;
}
void foo2() override {
cout << __PRETTY_FUNCTION__ << endl;
}
void futureFoo(Visit &visit) override {
visit.composite2(*this);
}
void operatorFoo(Foo &foo) override {
foo.operator()(*this);
}
};
//以后新增接口直接创建Visit子类就行
class Visit1 : public Visit {
public:
void composite1(Composite &composite) override {
cout << "新增函数" << endl;
}
void composite2(Composite &composite) override {
cout << "新增函数" << endl;
}
};
//以后新增接口直接创建Foo子类就行
class Foo1 : public Foo {
public:
void operator()(Composite1 &composite1) override {
cout << "新增函数" << endl;
}
void operator()(Composite2 &composite1) override {
cout << "新增函数" << endl;
}
};
// private:
// //foo是可以有参数的。
}
int main()
{
unVisit::Composite1().foo3();
unVisit::Composite2().foo3();
Visit::Visit1 foo3;
Visit::Composite1().futureFoo(foo3);
Visit::Composite2().futureFoo(foo3);
Visit::Foo1 _foo3;
Visit::Composite1().operatorFoo(_foo3);
Visit::Composite2().operatorFoo(_foo3);
return 0;
}
访问者模式
#include <iostream>
#include <memory>
using namespace std;
struct ConcreteElement1;
struct ConcreteElement2;
//访问者基类
struct Visitor{
virtual ~Visitor(){}
virtual void Visit(ConcreteElement1* element) = 0;
virtual void Visit(ConcreteElement2* element) = 0;
};
//被访问者基类
struct Element{
virtual ~Element(){}
virtual void Accept(Visitor& visitor) = 0;
};
//具体的访问者
struct ConcreteVisitor : public Visitor{
void Visit(ConcreteElement1 *element){
cout << "Visit ConcreteElement1" << endl;
}
void Visit(ConcreteElement2 *element){
cout << "Visit ConcreteElement2" << endl;
}
};
//具体的被访问者
struct ConcreteElement1 : public Element{
void Accept(Visitor& visitor){
visitor.Visit(this); //二次分派
}
};
//具体的被访问者
struct ConcreteElement2 : public Element{
void Accept(Visitor& visitor){
visitor.Visit(this);//二次分派
}
};
int main()
{
ConcreteVisitor v;
std::unique_ptr<Element> emt1(new ConcreteElement1());
std::unique_ptr<Element> emt2(new ConcreteElement2());
emt1->Accept(v);
emt2->Accept(v);
}
总结:
定义对象的结构类很少改变,但需要在结构之上定义新的结构
改变对象结构类需要重新定义对所有访问者的接口,改动太大
#include <iostream>
template<typename... Types>
struct Visitor;
template<typename T, typename... Types>
struct Visitor<T, Types...> : Visitor<Types...>
{
using Visitor<Types...>::Visit;//避免隐藏基类的同名方法
virtual void Visit(const T&) = 0;
};
template<typename T>
struct Visitor<T>
{
virtual void Visit(const T&) = 0;
};
struct stA;
struct stB;
struct Base
{
//定义通用的访问类型,它可以访问stA和stB
typedef Visitor<stA, stB> MytVisitor; //会自动生成stA和stB的visit虚函数,等同于如下
/*
struct Visitor<stA, stB>
{
virtual void Visit(const stA&) = 0;
virtual void Visit(const stB&) = 0;
};
*/
//增加新的访问者时,就如下
//typedef Visitor<stA, stB, stC, stD, stE> MytVisitor; //同样会自动生成对应的visit虚函数,类似stA和stB的过程
virtual void Accpet(MytVisitor&) = 0;
};
struct stA: Base
{
double val;
void Accpet(Base::MytVisitor& v){
v.Visit(*this);
}
};
struct stB: Base
{
int val;
void Accpet(Base::MytVisitor& v){
v.Visit(*this);
}
};
struct PrintVisitor: Base::MytVisitor
{
void Visit(const stA& a){
std::cout << "from stA" <<a.val<<std::endl;
}
void Visit(const stB& b){
std::cout << "from stB" <<b.val<<std::endl;
}
};
int main()
{
PrintVisitor vis;
stA a;
a.val = 8.97;
stB b;
b.val = 8;
Base *base = &a;
base->Accpet(vis);
base = &b;
base->Accpet(vis);
}
总结:
通过上述方式自动新增被访问者的虚函数, 实现visitor接口层不需要修改保持稳定
把需要visitor接口层变化转移到被访问者基类中,尽管增加新的访问者,基类中visitror类型需要扩展,但相对修改会比较小
4、改进命令模式
命令模式可用来消除程序中的耦合问题,例如以下
#include <iostream>
#include <vector>
#include <string>
#include <ctime>
#include <cstdlib>
using namespace std;
class Task
{
public:
virtual void operation() = 0;
};
//单例
class TaskRunner
{
public:
static void add(Task& t){
tasks.push_back(&t);
}
static void run(){
vector<Task*>::iterator it = tasks.begin();
while (it != tasks.end()) {
(*it++)->operation();
}
}
private:
static vector<Task*> tasks;
TaskRunner(){}
static TaskRunner tr;
};
TaskRunner TaskRunner::tr;
vector<Task*> TaskRunner::tasks;
//创建随机延迟时间
//clock() 返回从开启程序进程到调用clock()时的时间。
class EventSimulator
{
public:
EventSimulator():creation(clock()) {
delay = CLOCKS_PER_SEC/4 * (rand() % 20 + 1);
cout << "delay = " << delay << endl;
}
bool fired(){
return clock() > creation + delay;
}
private:
clock_t creation;
clock_t delay;
};
class Button{
public:
Button(string name):pressed(false),id(name){}
void press(){pressed = true;}
bool isPressed(){
if(e.fired()) press();
return pressed;
}
friend ostream& operator <<(ostream & os,const Button& b){
return os << b.id;
}
private:
bool pressed;
string id;
EventSimulator e;
};
class CheckButton : public Task
{
public:
CheckButton(Button & b):button(b),handled(false) {}
void operation(){
if(button.isPressed() && !handled){
cout << button << " pressed" << endl;
handled = true;
}
}
private:
Button & button;
bool handled;
};
void procedure1(){
TaskRunner::run(); // check all events
}
void procedure2(){
TaskRunner::run(); // check all events
}
void procedure3(){
TaskRunner::run(); // check all events
}
int main()
{
srand(time(0));
Button b1("Button 1"),b2("Button 2"),b3("Button 3");
CheckButton cb1(b1),cb2(b2),cb3(b3);
TaskRunner::add(cb1);
TaskRunner::add(cb2);
TaskRunner::add(cb3);
cout<< "Control-C to exit" << endl;
while (true) {
procedure1();
procedure2();
procedure3();
}
return 0;
}
/*
命令对象由被单例 TaskRunner执行的 Task 表示。EventSimulator创建一个随机延迟时间,所以当周期性的调用函数fired()时,在某个随机时间段,其返回结果从 true 和 false 变化。EventSimulator对象类 Button 中使用,模拟在某个不可预知的时间段用户时间发生的动作。CheckButton 是Task 的实现,在程序中通过所有“正常”代码对其进行周期性检查,就是这里的procedure1(),procedure2(),procedure3()的末尾
*/
总结:当请求越多,所需要的命令类也越多,导致类的爆炸
泛型简单命令类的实现
class Commond
{
public:
Commond();
~Commond();
virtual void Execute() = 0;
};
template<class Receiver>
class SimpleCommand : public Commond {
public:
typedef void (Receiver::*Action)();
SimpleCommand(Receiver *r, Action a):_receiver(r),_action(a){}
virtual void Execute();
private:
Action _action;
Receiver* _receiver;
};
template<class Receiver>
void SimpleCommand<Receiver>::Execute(){
(_receiver->*_action)();
}
class MyClass
{
public:
void Action();
};
int main()
{
MyClass* receiver = new MyClass;
Commond* aCommond = new SimpleCommand<MyClass>(receiver, &MyClass::Action);
aCommond->Execute();
return 0;
}
避免了不断创建新的命令类,但不能对所有的复杂的命令类泛化
解决问题的思路:
1)如何通用的泛化的所有命令类,让命令类接受所有的成员函数指针或者函数对象
#include <functional>
#include <type_traits>
#include <iostream>
using namespace std;
namespace CppHelper
{
template<typename Ret=void>
struct CCommand
{
private:
std::function < Ret()> m_func;
public:
//接受function、函数对象、lamda和普通函数的包装器
template< class Func, class... Args, class = typename std::enable_if<!std::is_member_function_pointer<Func>::value>::type>
void Wrap(Func && func, Args && ... args)
{
m_func = [&]{return func(args...); };
}
//接受常量成员函数的包装器
template<class CObj, class... DArgs, class PObj, class... Args>
void Wrap(Ret(CObj::*func)(DArgs...) const, PObj && pObj, Args && ... args)
{
m_func = [&, func]{return (*pObj.*func)( args...); };
}
//接受非常量成员函数的包装器
template<class CObj, class... DArgs, class PObj, class... Args>
void Wrap(Ret(CObj::*func)(DArgs...), PObj && pObj, Args && ... args)
{
m_func = [&, func]{return (*pObj.*func)( args...); };
}
Ret Excecute()
{
return m_func();
}
};
}
struct STA
{
int m_a;
int operator()(){ return m_a; }
int operator()(int n){ return m_a + n; }
int triple0(){ return m_a * 3; }
int triple(int a){ return m_a * 3 + a; }
int triple1() const { return m_a * 3; }
const int triple2(int a) const { return m_a * 3+a; }
void triple3(){ cout << "" <<endl; }
};
int add_one(int n)
{
return n + 1;
}
int main()
{
CppHelper::CCommand<int> cmd;
//普通函数
cmd.Wrap(add_one, 0);
cout << cmd.Excecute()<< endl;
//lambda表达式
cmd.Wrap([](int n){return n + 1; }, 1);
cout << cmd.Excecute()<< endl;
//函数对象
cmd.Wrap(STA());
cout << cmd.Excecute()<< endl;
cmd.Wrap(STA(), 4);
cout << cmd.Excecute()<< endl;
STA t = { 10 };
int x = 3;
//成员函数
cmd.Wrap(&STA::triple0, &t);
cout << cmd.Excecute()<< endl;
cmd.Wrap(&STA::triple, &t, x);
cout << cmd.Excecute()<< endl;
cmd.Wrap(&STA::triple, &t, 3);
cout << cmd.Excecute()<< endl;
//常量成员
CppHelper::CCommand<const int> cmd1;
cmd1.Wrap(&STA::triple2, &t, 3);
cout << cmd1.Excecute()<< endl;
CppHelper::CCommand<> cmd2;
cmd2.Wrap(&STA::triple3, &t);
cmd2.Excecute();
}
5、改进对象池模式
避免重复创建开销比较大的对象,通过对象池来优化
思路如下:
先创建好一批对象,放到集合中,每当程序需要新对象时,从对象池获取,用完归还对象池即可。避免重复创建对象,提高程序性能
#include <functional>
#include <iostream>
#include <map>
#include <memory>
using namespace std;
const int MaxObjectNum = 10;
template<typename T>
class ObjectPoll
{
template<typename... Args>
using Constructor = std::function<std::shared_ptr<T>(Args...)>;
public:
ObjectPoll():needClear(false){}
~ObjectPoll(){
needClear = true;
}
//默认创建多少个对象
template<typename... Args>
void Init(size_t num, Args&&... args){
if(num <= 0 || num > MaxObjectNum)
throw std::logic_error("object num out of range.");
auto construcrName = typeid(Constructor<Args...>).name();//不区分引用
for(size_t i = 0; i < num; i++){
m_object_map.emplace(construcrName, shared_ptr<T>(new T(std::forward<Args>(args)...), [this, construcrName](T* p){
return createPtr<T>(string(construcrName), args...);
}));
}
}
template<typename T, typename... Args>
std::shared_ptr<T> createPtr(std::string& construcrName, Args... args){
return std::shared_ptr<T>(new T(args...), [construcrName, this](T* t){
if(needClear)
delete[] t;
else
m_object_map.emplace(construcrName, std::shared_ptr<T>(t));
});
}
//从对象池获取一个对象
template<typename... Args>
std::shared_ptr<T> Get(){
string construcrName = typeid(Constructor<Args...>).name();
auto range = m_object_map.equal_range(construcrName); //二分查找
for(auto it = range.first; it != range.second; ++it){
auto ptr = it->second;
m_object_map.erase(it);
return ptr;
}
return nullptr;
}
private:
std::multimap<std::string, std::shared_ptr<T>> m_object_map;
bool needClear;
};
总结:
1)对象用完需要手动回收,存在忘记回收的风险
2)不支持参数不同的构造函数
上述问题两个问题在C++11中可如下解决:
1)使用智能指针实现自动回收
2)通过可变参数模板来解决
// ObjectPool.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <string>
#include <functional>
#include <memory>
#include <map>
using namespace std;
const int MaxObjectNum = 10;
class NonCopyable
{
protected:
NonCopyable() = default;
~NonCopyable() = default;
// 禁用复制构造
NonCopyable(const NonCopyable&) = delete;
// 禁用赋值构造
NonCopyable& operator = (const NonCopyable&) = delete;
};
template<typename T>
class ObjectPool :NonCopyable
{
template<typename...Args>
using Constructor = function<shared_ptr<T>(Args...)>;
public:
// 默认创建多少个对象
template<typename... Args>
void Init(size_t num, Args&&...args)
{
if (num <=0 || num>MaxObjectNum)
{
throw logic_error("object num out of range.");
}
// 不区分引用
auto constructName = typeid(Constructor<Args...>).name();
for (size_t i =0;i<num;i++)
{
m_object_map.emplace(constructName, shared_ptr<T>(new T(forward<Args>(args)...), [this, constructName](T*p) {
//删除器中不直接删除对象,而是回收到对象池中,以供下次使用
m_object_map.emplace(move(constructName), shared_ptr<T>(p));
}));
}
}
// 从对象池中获取一个对象
template<typename... Args>
shared_ptr<T> Get()
{
string constructName = typeid(Constructor<Args...>).name();
auto range = m_object_map.equal_range(constructName);
for (auto it = range.first; it != range.second;++it)
{
auto ptr = it->second;
m_object_map.erase(it);
return ptr;
}
return nullptr;
}
private:
multimap<string,shared_ptr<T>> m_object_map;
};
struct BigObject
{
BigObject() {}
BigObject(int a) {}
BigObject(const int& a, const int&b) {}
void Print(const string& str)
{
cout << str << endl;
}
};
void Print(shared_ptr<BigObject>p, const string& str)
{
if (p != nullptr)
{
p->Print(str);
}
}
void TestObjPool()
{
ObjectPool<BigObject> pool;
pool.Init(2);
{
auto p = pool.Get();
Print(p, "p");
auto p2 = pool.Get();
Print(p2, "p2");
// 出了作用哉之后,对象池返回出来的对象又会自动回收
}
auto p = pool.Get();
Print(p, "p");
auto p2 = pool.Get();
Print(p2, "p2");
// 对象池支持重载构造函数
pool.Init(2, 1);
auto p4 = pool.Get<int>();
Print(p4, "p4");
pool.Init(2, 1, 2);
auto p5 = pool.Get<int, int>();
Print(p5, "p5");
}
int main()
{
TestObjPool();
}
总结:
1)对象被回收之后,它的状态没有被清楚,从对象池模式去除来时最好重置一下状态
2)构造对象时,构造函数入参的引用将被忽略,即int和ini&会被认为时同一种构造函数,原因为构造对象的时候无法获取变参Args…的引用类型,丢失了引用相关信息