当前位置: 首页 > 科技观察

深入剖析C++对象池自动回收技术,实现

时间:2023-03-18 16:12:59 科技观察

对象池可显着提升性能。如果一个对象的创建非常耗时或者开销很大,那么频繁创建它的效率会很低。对象池通过对象重用避免了对象的重复创建。它会预先创建一定数量的对象并放入池中。当用户需要创建对象时,可以直接从对象池中获取。返回对象池重新使用。这种方法避免了重复创建耗时或耗资源的大对象,大大提高了程序性能。本文将讨论对象池的技术特点和源码实现。对象池类图ObjectPool:管理对象实例的池。客户:用户。适用性:类的实例是可重用的。类的实例化过程是昂贵的。类被更频繁地实例化。作用:节省了创建类实例的开销。节省创建类实例的时间。存储空间随着对象数量的增加而增加。问题看目前主流语言的实现,无外乎3步:初始创建一定数量的对象池(也允许从外部添加对象)。从对象池中获取一个对象来使用。使用后返回对象池。一般来说,这是可以的。可能的问题在第三步。有两个问题:不方便,每次都需要显式回收对象。忘记将对象放回对象池,造成资源浪费。提高解决显式回收问题的动力,实现自动回收,省心省力。改进后的对象池不需要提供release方法,对象会自动回收。改进后的类图如下。Technologyinsider使用c++11的智能指针,因为智能指针可以自定义删除器,当智能指针被释放时,删除器就会被调用。在删除器中,我们将使用过的对象放回对象池中。思路比较简单,但是在实现的时候需要考虑两个问题:什么时候定义deleter?使用shared_ptr还是unique_ptr?1.什么时候定义删除器自定义删除器只做一件事,就是把对象放回对象池中。如果在初始化对象池的时候自定义删除器,删除器中的逻辑就是将对象放回对象池。当你放回去的时候,你不能像这样定义另一个删除器,所以这种做法是行不通的。需要注意的是,被回收的对象只能是默认的deleter。除了前面提到的原因之外,还有一个原因就是释放对象池的时候需要释放所有的智能指针。如果释放时有自定义的删除器,则无法删除该对象。获取时只需要定义删除器即可,但最初创建或添加的智能指针是默认删除器,所以我们需要将智能指针的默认删除器改为自定义删除器。1.2使用shared_ptr或unique_ptr,因为我们需要将智能指针的默认删除器改为自定义删除器。使用shared_ptr不方便,因为不能直接将shared_ptr的deleter修改为自定义的deleter,虽然可以重新创建一个新对象并复制原对象来实现,但是这样效率比较低。因为unique_ptr具有排他语义,提供了一种简单的修改删除器的方法,所以unique_ptr是最合适的。1.3现实源码#pragmaonce#include#include#includetemplateclassSimpleObjectPool{public:usingDeleterType=std::function;voidadd(std::unique_ptrt){pool_.push_back(std::move(t));}std::unique_ptrget(){if(pool_.empty()){throwstd::logic_error("nomoreobject");}//每次添加自定义删除器fordefaultunique_ptrstd::unique_ptrptr(pool_.back().release(),[this](T*t){pool_.push_back(std::unique_ptr(t));});pool_.pop_back();returnstd::move(ptr);}boolempty()const{returnpool_.empty();}size_tsize()const{returnpool_.size();}private:std::vector>pool_;};//testcodevoidtest_object_pool(){SimpleObjectPoolp;p.add(std::unique_ptr(newA()));p.add(std::unique_ptr(newA()));{autot=p.get();p.get();}{p.get();p.get();}std::cout<get(){if(pool_.empty()){throwstd::logic_error("nomoreobject");}std::shared_ptrptr=pool_.back();autop=std::shared_ptr(newT(std::move(*ptr.get())),[this](T*t){pool_.push_back(std::shared_ptr(t));});//std::unique_ptrptr(pool_.back().release(),[this](T*t)//{//pool_.push_back(std::unique_ptr(t));//});pool_.pop_back();returnp;}该方法每次都需要创建一个新对象,并复制原对象,是一种比较低效的方式。代码只是为了展示如何实现对象的自动回收,没有考虑线程安全和对象池扩展策略等细节,源码链接:object_pool总结该方法可用于任何需要自动回收的场景:更改默认删除器获取对象删除器时自定义一个,确保它可以回收。注意回收的智能指针使用的是默认的删除器,可以保证对象池释放的时候可以正常释放对象。同时,在获取和释放对象时,完全分离了对象的控制权。其他一些应用场景:多实例模式,无需手动释放,自动回收。