为什么写简单对象池?因为我暂时想不到有什么值得完善的,如果有我还是非常乐意去搞搞看。

那么话不多说直接开搞。

什么是对象池?就是一个池子,里面有很多对象,你可以借出,借出后用完再还回去。为什么要有对象池这么东西显而易见,我们省去了对象的创建,岂不美哉?

那么我们的对象池既然要借出,就必须要有对象在里面,就像你去借共享单车,没有单车停在那里你借个啥?

那我们先写初始化,可以想象共享单车公司开始放单车了:

    ObjectPool(int Size):_MaxSize(Size){
        if(_MaxSize){
            for(int i = 0;i<_MaxSize;i++)
            {
                Object_List.push(new Object(i));
            }
        }
        else{
            printf("Init Error!\n");
        }
    }

可以看出来,只要_MaxSize值不为0,那就能成功初始化,顺便说一下我这里是new一个放一个,是写着方便,网上也有另外一种初始化方法。

    Object* pT = reinterpret_cast<Object*》(malloc(_MaxSize*sizeof(Object)));
    for(int i = 0;i<_MaxSize;i++)
    {
        (pT+i)->ID = i;
        Object_List.push(pT+i);
    }

这个大同小异,就是实现方法有点不同,是先申请那么多个内存,然后一段一段放回进去,这样申请出来的指针内存位置是连续的,我那种就不一定。另外就是一个很基础的东西,new对应delect,malloc对应free。

然后我们再来说借出:

    Object* Get_Object(){
        Object* object = Object_List.front();
        if(Object_List.empty()){
            printf("No Enough Object\n");
            object = new Object(999);
            return object;
        }
        else{
            object = Object_List.front();
            Object_List.pop();
            return object;
        }
    }

代码显而易见,只不过不要学我在处理队空时所申请内存的方法,怎么改都行,不难。

最后是放回,也非常简单:

void Give_Back(Object* object){
    if(Object_List.size()==_MaxSize){
        printf("Delect %d!\n",object->ID);
        delete object;
    } else {
        printf("Push %d Back!\n",object->ID);

        Object_List.push(object);
    }
}

然后我们来测试一下:

int main(){
ObjectPool newPool(3);
Object* item_1 = newPool.Get_Object();
Object* item_2 = newPool.Get_Object();
Object* item_3 = newPool.Get_Object();

PrintAddress(item_1);
PrintAddress(item_2);
PrintAddress(item_3);

newPool.Give_Back(item_1);
Object* item_4 = newPool.Get_Object();
PrintAddress(item_4);
}

结果是:

This is an Object ID = 0 and Address is 0x7ff8b4c02590 
This is an Object ID = 1 and Address is 0x7ff8b4c02594 
This is an Object ID = 2 and Address is 0x7ff8b4c02598 
Push 0 Back!
This is an Object ID = 0 and Address is 0x7ff8b4c02590 

完全符合我们的预期,那最后来做个有意思的模拟吧,从这个模拟顺便说说线程池的缺点,前面叨叨了那么多共享单车,我们假设每个线程池是一个地方,每个物体是一个共享单车,我们现在来模拟一下一段时间内这些车被人骑走还回的情况。

#include<cstdio>
#include <queue>
class Bike{
public:
    int _ID;
    int _NowWhere;
    Bike(int ID,int NowWhere){
        this->_ID = ID;
        this->_NowWhere = NowWhere;
    }
    void MoveTo(int NextWhere){
        _NowWhere = NextWhere;
        printf("This Bike is move to %d\n", NextWhere);
    }
};

class Place{
    int _MaxSize;
public:

    int _PlaceID;
    std::queue<Bike*> Object_List;
    Place(int Size,int PlaceID):_MaxSize(Size){
        _PlaceID = PlaceID;
        if(_MaxSize){
            Bike* pT = reinterpret_cast<Bike*>(malloc(_MaxSize*sizeof(Bike)));
            for(int i = 0;i<_MaxSize - 5;i++)
            {
                (pT+i)->_ID = i;
                (pT+i)->_NowWhere = _PlaceID;
                Object_List.push(pT+i);
            }
        }
        else{
            printf("Init Error!\n");
        }
    }

     Bike* Borrow(){
        Bike* object = Object_List.front();
        if(Object_List.empty()){
            printf("Sorry , No Bike To Borrow !\n");
            return object;
        }
        else{
            object = Object_List.front();
            Object_List.pop();
            return object;
        }
    }
    void Give_Back(Bike* object){
        if(Object_List.size()==_MaxSize){
            printf("Error!\n");
        } else {
            printf("%d is Give Back at %d!\n",object->_ID,object->_NowWhere);
            Object_List.push(object);


        }
    }
    int GetMaxSize(){
        return _MaxSize;
    }
};
void GetSum(Place& a,Place& b,Place& c)
{
    printf("***************\nThere are %lu bike at TianHeCity!\nThere are %lu bike at ZhujiangCity!\nThere are %lu bike at WushanStation!\n***************\n",a.Object_List.size(),b.Object_List.size(),c.Object_List.size());
}
void RideAway(Bike* Bike_Item,Place& NextPlace){
    Bike_Item->MoveTo(NextPlace._PlaceID);
    NextPlace.Give_Back(Bike_Item);
}
int main(){
    Place TianHeCity(10,1);
    Place ZhuJiangCity(10,2);
    Place WuShanStation(10,3);
    GetSum(TianHeCity,ZhuJiangCity,WuShanStation);

    if(Bike* Bike_1 = TianHeCity.Borrow())
    {
        RideAway(Bike_1,ZhuJiangCity);
    }

    if(Bike* Bike_2 = TianHeCity.Borrow())
    {
        RideAway(Bike_2,ZhuJiangCity);
    }

    if(Bike* Bike_3 = TianHeCity.Borrow())
    {
        RideAway(Bike_3,ZhuJiangCity);
    }

    if(Bike* Bike_4 = TianHeCity.Borrow())
    {
        RideAway(Bike_4,ZhuJiangCity);
    }

    if(Bike* Bike_5 = TianHeCity.Borrow())
    {
        RideAway(Bike_5,ZhuJiangCity);
    }

    if(Bike* Bike_6 = TianHeCity.Borrow())
    {
        RideAway(Bike_6,ZhuJiangCity);
    }

    GetSum(TianHeCity,ZhuJiangCity,WuShanStation);
}

下面main函数写的有点弱智,但是方便阅读。可以看到大家都喜欢从天河城骑车去珠江新城,所以天河城被骑到没车了,而珠江新城一堆车,幸好珠江新城地方比较大能停,如果不能停就糟糕了。

一般的对象池如果满了,会选择直接删除,但是如果你是写共享单车对象池的人,肯定不能把车直接扔了,老板不杀了你才怪。这个时候我们有别的解决方法,这里提供一个思路:可以给Give_Back添加返回值,如果没有归还成功就返回一个有位置的对象池,实现这个功能需要借助一个外部函数,但是不难,所以不写了,这里着重说一下对象池最大的一个问题。

想象这里突然来了一个缺德的人,拿了车不还,我们在统计车数的时候就会发现如下信息:

***************
There are 0 bike at TianHeCity!
There are 9 bike at ZhujiangCity!
There are 5 bike at WushanStation!
***************

惨了少了一辆,现实中我们损失的是资金,但是在程序中,我们就等于失去了一块内存,你不还还去借下一个,那就会导致内存泄露,这个是在事发后没有办法解决的问题,所以要么就完善对象池让他自动回收(利用析构函数),要么就记得要还。

OK,对象池就写这么多。