工厂模式和对象池

工厂模式和对象池

c++下构造一个对象一般的做法是采用new&delete

复制代码
class exp{
//anything }; exp
*p = new exp; //do anything delete p;
复制代码

考虑到new&delete本身的实现,背后的内存管理采用的是统一的malloc&free,如果要对不同的类型采用不同的内存管理策略,就需要对不同的类类型重载new&delete操作符

复制代码
class exp1{
public:
    //any thing
public:
    void * operator new(size_t size){
        return malloc(size);
    }

    void operator delete(void *p){
        free(p);
    }

    void * operator new[ ](size_t size){
        return malloc(size);
    }

    void operator delete[ ](void *p){
        free(p);
    }        
};    

class exp2{
public:
    //any thing
    std::allocator<exp2> alloc;
public:
    void * operator new(size_t size){
        return alloc.allocate(1);
    }

    void operator delete(void *p){
        alloc.deallocate((exp2*)ptr, 1);
    }

    void * operator new[ ](size_t size){
        return alloc.allocate(size/sizeof(exp2));
    }

    void operator delete[ ](void *p, size_t size){
        alloc.deallocate((exp2*)ptr, size/sizeof(exp2));
    }        
};    
复制代码

或是另一个做法,对不同的类型构造采用硬编码

复制代码
//exp1
class exp1{
//any thing
};

std::allocator<exp1> alloc;
exp1 * p = alloc(1);
new(p) exp1();
//do anything
p->~expq();
alloc.deallocate((exp1*)ptr, 1);

//exp2
class exp2{
//any thing
};

exp2 * p = nedmalloc(siezof(exp2));
new(p) exp2();
//do anything
p->~exp2();
nedfree(p);
复制代码

不过这2种做法都需要多写大量繁琐的代码。依赖于C++的模板机制,我们可以写出如下的简化代码,

复制代码
template <typename T, typename _Allocator_ = boost::pool_allocator<T> >
class abstract_factory{
public:
    abstract_factory(){
    }

    ~abstract_factory(){
    }

    T * create_product(){
        T * pT =  (T*)_Allocator.allocate(1);
        new(pT) T();
        
        return pT;
    }
        
        void release_product(T * pT){
        pT->~T();
                _Allocator.deallocate(pT, 1);
        }          
}
复制代码

考虑到支持带参数的构造函数,我写了一坨丑陋的代码

复制代码
template <typename t1> 
T * create_product(t1 _t1);

template <typename t1, typename t2>
T * create_product(t1 _t1, t2 _t2);

//...

template <typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8, typename t9, typename t10>
T * create_product(t1 _t1, t2 _t2, t3 _t3, t4 _t4, t5 _t5, t6 _t6, t7 _t7, t8 _t8, t9 _t9, t10 _t10);
复制代码

这样对象的创建我们就可以采用如下写法

复制代码
class exp1{
public:
     exp1(int n) : a(n){}
     ~exp1(){}

private:
     int a;
}

abstract_factory<exp1> _afexp1;
shared_ptr pexp1(_afexp1.create_product(1), bind(&abstract_factory<exp1>::release_product, &_afexp1, _1));
//do anything
复制代码

这陀东西比较糟糕的一个地方是,只支持一次创建一个对象,原因是背后的对象池的管理机制,我采用了一种有趣的做法,就是对回收的对象析构之后,在回收的内存上保存上次回收的内存地址,以此来实现了一个链式的结构。

但是数组本身也可以采用vector之类的现有容器

class exp1{
//any thing
};

std::vector<exp1> vexp1;

 为了提高在多线程下的访问效率,我采用了一种类似thread-cache的做法,就是将一个对象链表视为一个mirco_pool,创建多个mirco_pool。通过为每个mirco_pool加锁,访问mirco_pool时先尝试try_lock,失败则对下一个mirco_pool尝试try_lock,成功后再执行分配&构造或是析构回收操作,来降低锁竞争的开销。

复制代码
for(uint32_t i = 0; i < count; i++){
    boost::mutex::scoped_lock lock(_mirco_pool[i]._mu, boost::try_to_lock);

    if (lock.owns_lock()){
        if (_mirco_pool[i]._pool != 0){
            pT = (T*)_mirco_pool[i]._pool;
            _mirco_pool[i]._pool = *((char**)_mirco_pool[i]._pool);

            break;
        }
    }
}
复制代码

代码地址:https://github.com/qianqians/Hemsleya/blob/master/base/concurrent/abstract_factory/abstract_factory.h

参考阅读:

抽象工厂模式 http://zh.wikipedia.org/zh-cn/%E6%8A%BD%E8%B1%A1%E5%B7%A5%E5%8E%82

对象池 http://baike.baidu.com/view/262255.htm

原文地址:https://www.cnblogs.com/Leo_wl/p/3295712.html