对象池

文章目录
  1. 1. 简单实现
  2. 2. 一个支持自动回收的对象池实现
  • 参考资料
  • 对象池对于创建开销比较大的对象来说很有意义,为了避免重复创建开销比较大的对象,我们可以通过对象池来优化。对象池的思路比较简单,事先创建好一批对象,放到一个集合中,以后每当程序需要新的对象时候,都从对象池里获取,每当程序用完该对象后,都把该对象归还给对象池。这样会避免重复的对象创建,提高程序性能。

    简单实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    #include <list>

    template<typename Object>
    class ObjectPool
    {
    public:

    ObjectPool(size_t unSize) :
    m_unSize(unSize)
    {
    for (size_t unIdx = 0; unIdx < m_unSize; ++ unIdx) {
    m_oPool.push_back(new Object());
    }
    }

    ~ObjectPool()
    {
    typename std::list<Object *>::iterator oIt = m_oPool.begin();
    while (oIt != m_oPool.end())
    {
    delete (*oIt);
    ++ oIt;
    }
    m_unSize = 0;
    }

    Object * GetObject()
    {
    Object * pObj = NULL;
    if (0 == m_unSize)
    {
    pObj = new Object();
    }
    else
    {
    pObj = m_oPool.front();
    m_oPool.pop_front();
    -- m_unSize;
    }

    return pObj;
    }

    void ReturnObject(Object * pObj)
    {
    m_oPool.push_back(pObj);
    ++ m_unSize;
    }

    private:
    size_t m_unSize;
    std::list<object *> m_oPool;
    };

    不足点如下:

    1. 对象池ObjectPool只能容纳特定类型的对象,不能容纳所有类型的对象,可以支持重载的和参数不同的构造函数;
    2. 对象用完之后需要手动回收,用起来不够方便,更大的问题是存在忘记回收的风险;

    希望能有一个更强大的对象池,这个对象池能容纳所有的对象,还能自动回收用完了对象,不需要手动回收,用起来更方便。要实现这样的对象池需要解决前面提到的两个问题,通过c++11就可以解决这两个问题。

      对于问题1:容纳所有的对象。本质上需要将对象池中的对象类型擦除,这里用Any类型就可以解决。

      对于问题2:自动回收用完的对象。这里用智能指针就可以解决,在创建智能指针时可以指定删除器,在删除器中不删除对象,而是回收到对象池中,而这个过程对外界来说是看不见的,由智能指针自己完成。

    ​ 暂时不考虑解决问题一。

    一个支持自动回收的对象池实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    #ifndef IG_SHARED_OBJECT_POOL_H_
    #define IG_SHARED_OBJECT_POOL_H_

    #include <cstdlib>
    #include <queue>
    #include <vector>
    #include <list>
    #include <memory>

    namespace ig {

    static const size_t kObjectPoolDefaultSize = 100;
    static const size_t kObjectPoolDefaultExtendSize = 10;

    template <typename ObjectType>
    struct ObjectPoolDefaultInitializer {
    void operator()(ObjectType *object) const {
    }
    };

    template <typename ObjectType, size_t N = kObjectPoolDefaultSize,
    typename Initializer = ObjectPoolDefaultInitializer<ObjectType> >
    class SharedObjectPool {
    public:
    static SharedObjectPool& Instance() {
    static SharedObjectPool pool(N);
    return pool;
    }

    std::shared_ptr<ObjectType> Get() {
    ObjectType *ptr = nullptr;
    if (queue_.empty()) {
    Extend(kObjectPoolDefaultExtendSize);
    }
    ptr = queue_.front();
    queue_.pop();
    kInitializer(ptr);
    return std::shared_ptr<ObjectType>(ptr, [&](ObjectType *p) {
    queue_.push(p);
    });
    }

    int capacity() const {
    return capacity_;
    }

    void set_capacity(const size_t capacity) {
    if (capacity_ < capacity) {
    Extend(capacity - capacity_);
    }
    }

    private:
    explicit SharedObjectPool(const size_t pool_size) :
    kDefaultCacheSize(pool_size) {
    cache_ = new ObjectType[kDefaultCacheSize];
    for (size_t i = 0; i < kDefaultCacheSize; ++i) {
    queue_.push(&cache_[i]);
    kInitializer(&cache_[i]);
    }
    capacity_ = kDefaultCacheSize;
    }

    ~SharedObjectPool() {
    if (cache_) {
    delete[] cache_;
    cache_ = nullptr;
    }
    for (auto &ptr : extended_cache_) {
    delete ptr;
    }
    extended_cache_.clear();
    }

    void Extend(const size_t num) {
    for (size_t i = 0; i < num; ++i) {
    ObjectType *ptr = new ObjectType;
    extended_cache_.push_back(ptr);
    queue_.push(ptr);
    kInitializer(ptr);
    }
    capacity_ = kDefaultCacheSize + extended_cache_.size();
    }

    private:
    size_t capacity_ = 0;

    std::queue<ObjectType*> queue_;

    ObjectType *cache_ = nullptr;

    std::list<ObjectType*> extended_cache_;

    const size_t kDefaultCacheSize;

    static const Initializer kInitializer;
    };

    template <typename ObjectType, size_t N, typename Initializer>
    const Initializer
    SharedObjectPool<ObjectType, N, Initializer>::kInitializer;
    } // namespace ig

    #endif // IG_SHARED_OBJECT_POOL_H_

    参考资料