博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
thinking in object pool
阅读量:6568 次
发布时间:2019-06-24

本文共 2590 字,大约阅读时间需要 8 分钟。

1.背景 

 对象池为了避免频繁创建耗时或耗资源的大对象,事先在对象池中创建好一定数量的大对象,然后尽量复用对象池中的对象,用户用完大对象之后放回对象池。

2.问题 

 目前纵观主流语言的实现方式无外乎3个步骤:

  1. 初始创建一定数量的对象池(也允许从外面添加对象)。
  2. 从对象池中取对象来使用。
  3. 用完之后返回对象池。

一般情况下这样是OK的,可能存在的问题是在第三步,有两个问题:

  1. 不方便,每次都需要显式回收对象。
  2. 忘记将对象放回对象池,造成资源浪费。

3.改进动机 

 解决显式回收的问题,实现自动回收,省心省力。

4.技术内幕

借助c++智能指针,因为智能指针可以自定义删除器,在智能指针释放的时候会调用删除器,在删除器中我们将用完的对象重新放回对象池。思路比较简单,但实现的时候需要考虑两个问题:

  1. 什么时候定义删除器?
  2. 用shared_ptr还是unique_ptr? 

4.1什么时候定义删除器

  自定义删除器只做一件事,就是将对象重新放入对象池。如果对象池初始化的时候就自定义删除器的话,删除器中的逻辑是将对象放回对象池,放回的时候无法再定义一个这样的删除器,所以这种做法行不通。

需要注意,回收的对象只能是默认删除器的。除了前述原因之外,另外一个原因是对象池释放的时候需要释放所有的智能指针,释放的时候如果存在自定义删除器将会导致对象无法删除。
只有在get的时候定义删除器才行,但是初始创建或加入的智能指针是默认删除器,所以我们需要把智能指针的默认删除器改为自定义删除器。 

4.2用shared_ptr还是unique_ptr

  因为我们需要把智能指针的默认删除器改为自定义删除器,用shared_ptr会很不方便,因为你无法直接将shared_ptr的删除器修改为自定义删除器,虽然你可以通过重新创建一个新对象,把原对象拷贝过来的做法来实现,

但是这样做效率比较低。而unique_ptr由于是独占语义,提供了一种简便的方法方法可以实现修改删除器,所以用unique_ptr是最适合的。 

4.3实现源码

#pragma once#include 
#include
#include
template
class SimpleObjectPool{public: using DeleterType = std::function
; void add(std::unique_ptr
t) { pool_.push_back(std::move(t)); } std::unique_ptr
get() { if (pool_.empty()) { throw std::logic_error("no more object"); } //every time add custom deleter for default unique_ptr std::unique_ptr
ptr(pool_.back().release(), [this](T* t) { pool_.push_back(std::unique_ptr
(t)); }); pool_.pop_back(); return std::move(ptr); } bool empty() const { return pool_.empty(); } size_t size() const { return pool_.size(); }private: std::vector
> pool_;}; //测试代码:void test_object_pool(){ SimpleObjectPool
p; p.add(std::unique_ptr
(new A())); p.add(std::unique_ptr
(new A())); { auto t = p.get(); p.get(); } { p.get(); p.get(); } std::cout << p.size() << std::endl;}

 如果你坚持用shared_ptr,那么回收的时候你需要这样写:

std::shared_ptr
get() { if (pool_.empty()) { throw std::logic_error("no more object"); } std::shared_ptr
ptr = pool_.back(); auto p = std::shared_ptr
(new T(*ptr.get()), [this](T* t) { pool_.push_back(std::shared_ptr
(t)); }); //std::unique_ptr
ptr(pool_.back().release(), [this](T* t) //{ // pool_.push_back(std::unique_ptr
(t)); //}); pool_.pop_back(); return p; }

 这种方式需要每次都创建一个新对象,并且拷贝原来的对象,是一种比较低效的做法。 

5.总结

  凡是需要自动回收的场景下都可以使用这种方式:在获取对象的时候将默认删除器改为自定义删除器,确保它可以回收。注意,回收的智能指针使用的是默认删除器,可以确保对象池释放时能正常释放对象。同时也将获取对象和释放对象时,对象的控制权完全分离。

  其他的一些应用场景:多例模式,无需手动释放,自动回收。 

转载地址:http://kdpjo.baihongyu.com/

你可能感兴趣的文章
代码文件的编码不统一导致的坑
查看>>
20145240《信息安全系统设计基础》第十二周学习总结
查看>>
物理机_双机调试_资料
查看>>
slice,substr和substring的区别
查看>>
C#Arcengine通过坐标点生成面(环形)
查看>>
7.08 计算累计差
查看>>
inline-block 间距
查看>>
Android深入浅出系列之实例应用—简单的手指拖动图片,图片滑来滑去显示应用Gallery和BaseAdapter以及ImageView的使用...
查看>>
MongoDB 基本操作增删改查
查看>>
关于github failed to push some refs
查看>>
Compiling: main.cpp /bin/sh: g++: not found
查看>>
课堂练习(续)
查看>>
linux每日命令(15):tail命令
查看>>
javascript基础系列(入门前须知)
查看>>
uLua中遇到的问题
查看>>
Python 三元条件判断表达式(and or/if else)
查看>>
grep, sed, awk
查看>>
0510JS基础:定义、输出、变量
查看>>
C++——友元 friend
查看>>
IPC——线程信号问题
查看>>