对象池概述:
对象池模型创建并拥有固定数量的对象,当程序需要一个新的对象时,如果对象池中有空闲对象,则立即返回,否则才创建新的该类对象。当一个对象不再被使用时,其应该应该将其放回对象池,以便后来的程序使用。由于系统资源有限,一个对象池模型应该指定其可容纳的最大对象数量。当达到该数量时,如果仍然有对象创建请求,则抛出异常或者阻塞当前调用线程,直到一个对象被放回对象池中。
对象池模型适用的场景:
(1)需要使用大量对象
(2)这些对象的实例化开销比较大且生存期比较短
对象池优势:
一个对象池可以在可容忍时间内创建成功并投入使用。但是创建对象时并不总是这样,尤其是当这些对象的创建过程比较耗时,而且创建和销毁频率又比较大时更是如此。比如数据库连接、网络套接字连接、线程对象、诸如字体或位图等图像对象等。
实现:
假设有如下类定义:
1 class Object 2 { 3 public: 4 Object(const string& name) : name_(name) 5 { 6 printf("Construct Object[%p] %s.\n", this, name_.c_str()); 7 } 8 9 ~Object() 10 { 11 printf("~Destruct Object[%p] %s.\n", this, name_.c_str()); 12 } 13 14 const string& key() const { return name_; } 15 16 private: 17 string name_; 18 };
如下对象池类的设计,用来提供Object类对象,分为2个版本介绍:(注意,如下仅考虑了对象池本身所涉及的特性,没有涉及同步控制机制)
版本1:
1 class ObjectPool 2 { 3 public: 4 boost::shared_ptr<Object> get(const string& key) 5 { 6 boost::shared_ptr<Object> pObject; 7 boost::weak_ptr<Object>& k_object = objects_[key]; 8 pObject = k_object.lock(); 9 if (!pObject) 10 { 11 pObject.reset(new Object(key), 12 boost::bind(&ObjectPool::releaseObject, this, _1)); 13 k_object = pObject; 14 } 15 return pObject; 16 } 17 18 private: 19 void releaseObject(Object* object) 20 { 21 printf("releaseObject[%p].\n", object); 22 if (object) 23 { 24 objects_.erase(object->key()); 25 } 26 delete object; 27 } 28 29 std::map<string, boost::weak_ptr<Object> > objects_; 30 };
ObjectPool的get函数返回map中key对应的Object对象。如果该对象不存在,则新建一个Object,将其放入map中,然后返回这个新建的Object。同时,重置shared_ptr(新增Object对象)时指定析构器releaseObject,使得对象析构时执行releaseObject(object);
但是上述实现存在一个问题:将this传入bind函数中,如果ObjectPool对象先于Object对象析构了,那么在析构Object对象时,如何调用releaseObject函数呢?(因为releaseObject函数属于ObjectPool类)
版本2:
1 class ObjectPool : public boost::enable_shared_from_this<ObjectPool> 2 { 3 public: 4 boost::shared_ptr<Object> get(const string& key) 5 { 6 boost::shared_ptr<Object> pObject; 7 boost::weak_ptr<Object>& k_object = objects_[key]; 8 pObject = k_object.lock(); 9 if (!pObject) 10 { 11 pObject.reset(new Object(key), 12 boost::bind(&ObjectPool::releaseObject, shared_from_this(), _1)); 13 k_object = pObject; 14 } 15 return pObject; 16 } 17 18 private: 19 void releaseObject(Object* object) 20 { 21 printf("releaseObject[%p].\n", object); 22 if (object) 23 { 24 objects_.erase(object->key()); 25 } 26 delete object; 27 } 28 29 std::map<string, boost::weak_ptr<Object> > objects_; 30 };
要解决版本1中的问题,只需增加ObjectPool的寿命就可以了。可以利用boost::enable_shared_from_this模板类中的shared_from_this(),如此可以将this转换为shared_ptr<ObjectPool>。如此,由于bind是值传递语义,因此其必然保存一份shared_ptr<ObjectPool>的副本,可以保证shared_ptr的引用计数不为0。