对象池技术可以避免在程序的生命期中创建和删除大量对象。如果知道程序需要同一类型的大量对象,而且对象的生命周期都很短,就可以为这些对象创建一个池(pool)进行缓存。只要代码中需要一个对象,就可以向对象池请求.用完此对象时,要把它放回池中。对象池只创建一次对象,因此它们的构造函数只调用一次,而不是每次使用时都调用。因此,当构造函数要完成一些设置动作,而且这些设置可以应用与该对象的多次使用时,对象池就很适用。另外在非构造函数方法调用中要在对象上设置特定于实例的参数时,也很适用采用对象池。

一个对象池的实现

这里提供了一个池类对象的模板的实现,你可以在自己的程序中使用这个池实现。这个池在构造时会分配一大块(chunk)指定类的对象(这里的“块”,可以理解为包括许多对象,即一堆对象),并通过 acquireObject( ) 方法交出对象。当客户用完这个对象时,会通过 releaseObject( ) 方法将其返回。如果调用了 acquireObject( ) ,但是没有空闲的对象,池会分配另外一块对象。

对象池实现中最难的一方面是要记录哪些对象是空闲的,哪些对象正在使用。这个实现采用以下做法,即把空闲的对象保存在一个队列中。每次客户请求一个对象时,池就会把队列中第一个对象交个客户。这个池不会显式地跟踪正在使用的对象。它相信客户在用完对象后会正确的把对象交还到池中。另外,这个池在一个向量中记录所有已分配的对象。这个向量仅在撤销池时才会用到,以便是否所有对象的内存,从而避免内存泄露。

以下是类的定义,要注意,这个模板是基于相应的类类型(要在池中构造何种类型的对象)参数化的。

[cpp] view plain copy print?

  1. #include <queue>

  2. #include <vector>

  3. #include <stdexcept>

  4. #include <memory>

  5. using std::queue;

  6. using std::vector;

  7. //

  8. // template class ObjectPool

  9. //

  10. // Provides an object pool that can be used with any class that provides a

  11. // default constructor.

  12. //

  13. // The object pool constructor creates a pool of objects, which it hands out

  14. // to clients when requested via the acquireObject() method. When a client is

  15. // finished with the object it calls releaseObject() to put the object back

  16. // into the object pool.

  17. //

  18. // The constructor and destructor on each object in the pool will be called only

  19. // once each for the lifetime of the program, not once per acquisition and release.

  20. //

  21. // The primary use of an object pool is to avoid creating and deleting objects

  22. // repeatedly. The object pool is most suited to applications that use large

  23. // numbers of objects for short periods of time.

  24. //

  25. // For efficiency, the object pool doesn't perform sanity checks.

  26. // Expects the user to release every acquired object exactly once.

  27. // Expects the user to avoid using any objects that he or she has released.

  28. //

  29. // Expects the user not to delete the object pool until every object

  30. // that was acquired has been released. Deleting the object pool invalidates

  31. // any objects that the user had acquired, even if they had not yet been released.

  32. //

  33. template <typename T>

  34. class ObjectPool

  35. {

  36. public:

  37. //

  38. // Creates an object pool with chunkSize objects.

  39. // Whenever the object pool runs out of objects, chunkSize

  40. // more objects will be added to the pool. The pool only grows:

  41. // objects are never removed from the pool (freed), until

  42. // the pool is destroyed.

  43. //

  44. // Throws invalid_argument if chunkSize is <= 0.

  45. //

  46. ObjectPool(int chunkSize = kDefaultChunkSize)

  47. throw(std::invalid_argument, std::bad_alloc);

  48. //

  49. // Frees all the allocated objects. Invalidates any objects that have

  50. // been acquired for use.

  51. //

  52. ~ObjectPool();

  53. //

  54. // Reserve an object for use. The reference to the object is invalidated

  55. // if the object pool itself is freed.

  56. //

  57. // Clients must not free the object!

  58. //

  59. T& acquireObject();

  60. //

  61. // Return the object to the pool. Clients must not use the object after

  62. // it has been returned to the pool.

  63. //

  64. void releaseObject(T& obj);

  65. protected:

  66. //

  67. // mFreeList stores the objects that are not currently in use

  68. // by clients.

  69. //

  70. queue<T*> mFreeList;

  71. //

  72. // mAllObjects stores pointers to all the objects, in use

  73. // or not. This vector is needed in order to ensure that all

  74. // objects are freed properly in the destructor.

  75. //

  76. vector<T*> mAllObjects;

  77. int mChunkSize;

  78. static const int kDefaultChunkSize = 10;

  79. //

  80. // Allocates mChunkSize new objects and adds them

  81. // to the mFreeList.

  82. //

  83. void allocateChunk();

  84. static void arrayDeleteObject(T* obj);

  85. private:

  86. // Prevent assignment and pass-by-value

  87. ObjectPool(const ObjectPool<T>& src);

  88. ObjectPool<T>& operator=(const ObjectPool<T>& rhs);

  89. };

  90. template<typename T>

  91. const int ObjectPool<T>::kDefaultChunkSize;

  92. template <typename T>

  93. ObjectPool<T>::ObjectPool(int chunkSize) throw(std::invalid_argument,

  94. std::bad_alloc) : mChunkSize(chunkSize)

  95. {

  96. if (mChunkSize <= 0) {

  97. throw std::invalid_argument("chunk size must be positive");

  98. }

  99. // Create mChunkSize objects to start

  100. allocateChunk();

  101. }

  102. //

  103. // Allocates an array of mChunkSize objects because that's

  104. // more efficient than allocating each of them individually.

  105. // Stores a pointer to the first element of the array in the mAllObjects

  106. // vector. Adds a pointer to each new object to the mFreeList.

  107. //

  108. template <typename T>

  109. void ObjectPool<T>::allocateChunk()

  110. {

  111. T* newObjects = new T[mChunkSize];

  112. mAllObjects.push_back(newObjects);

  113. for (int i = 0; i < mChunkSize; i++) {

  114. mFreeList.push(&newObjects[i]);

  115. }

  116. }

  117. //

  118. // Freeing function for use in the for_each algorithm in the

  119. // destructor.

  120. //

  121. template<typename T>

  122. void ObjectPool<T>::arrayDeleteObject(T* obj)

  123. {

  124. delete [] obj;

  125. }

  126. template <typename T>

  127. ObjectPool<T>::~ObjectPool()

  128. {

  129. // free each of the allocation chunks

  130. for_each(mAllObjects.begin(), mAllObjects.end(), arrayDeleteObject);

  131. }

  132. template <typename T>

  133. T& ObjectPool<T>::acquireObject()

  134. {

  135. if (mFreeList.empty()) {

  136. allocateChunk();

  137. }

  138. T* obj = mFreeList.front();

  139. mFreeList.pop();

  140. return (*obj);

  141. }

  142. template <typename T>

  143. void ObjectPool<T>::releaseObject(T& obj)

  144. {

  145. mFreeList.push(&obj);

  146. }

对于这个类定义有几点需要强调。首先,要注意,对象是按引用获取和释放的,而不是按指针,这样可以避免客户通过指针管理或释放对象。接下来,注意对象池的用户通过模板参数来指定可以创建哪一个类的对象(即类名),通过构造函数指定分配的“块大小”。这个“块大小”控制着一次可创建的对象数。以下是定义 kDefaultChunkSize 的代码:

[cpp] view plain copy print?

  1. template<typename T>

  2. const int ObjectPool<T>::kDefaultChunkSize;

根据类定义,默认值 10 对于大多数使用来说可能都太小了.如果程序一次需要成千上万的对象,就应该使用一个更大、更适合的值。

构造函数验证 chunkSize 参数,并调用 allocateChunk( ) 辅助方法来得到起始的对象分配。

[cpp] view plain copy print?

  1. template <typename T>

  2. ObjectPool<T>::ObjectPool(int chunkSize) throw(std::invalid_argument,

  3. std::bad_alloc) : mChunkSize(chunkSize)

  4. {

  5. if (mChunkSize <= 0) {

  6. throw std::invalid_argument("chunk size must be positive");

  7. }

  8. // Create mChunkSize objects to start

  9. allocateChunk();

  10. }

allocateChunk( ) 方法在连续地存储空间中分配 mChunkSize 个元素。它会在一个 mAllObjects vector 中存储对象数组的指针,并把各个对象压至 mFreeLlist queue。

[cpp] view plain copy print?

  1. //

  2. // Allocates an array of mChunkSize objects because that's

  3. // more efficient than allocating each of them individually.

  4. // Stores a pointer to the first element of the array in the mAllObjects

  5. // vector. Adds a pointer to each new object to the mFreeList.

  6. //

  7. template <typename T>

  8. void ObjectPool<T>::allocateChunk()

  9. {

  10. T* newObjects = new T[mChunkSize];

  11. mAllObjects.push_back(newObjects);

  12. for (int i = 0; i < mChunkSize; i++) {

  13. mFreeList.push(&newObjects[i]);

  14. }

  15. }

析构函数只是释放 allocateChunk( ) 中分配的所有对象数组。不过,它使用了 for_each( ) STL算法来做到这一点,在此向 for_each( ) 传递一个arrayDelete( ) 静态方法的指针,这个方法会对各个对象数组具体完成删除调用。

[cpp] view plain copy print?

  1. //

  2. // Freeing function for use in the for_each algorithm in the

  3. // destructor.

  4. //

  5. template<typename T>

  6. void ObjectPool<T>::arrayDeleteObject(T* obj)

  7. {

  8. delete [] obj;

  9. }

  10. template <typename T>

  11. ObjectPool<T>::~ObjectPool()

  12. {

  13. // free each of the allocation chunks

  14. for_each(mAllObjects.begin(), mAllObjects.end(), arrayDeleteObject);

  15. }

acquireObject( ) 会返回空闲列表中的队头对象,如果没有空闲对象则首先调用 allocateChunk( ) 。

[cpp] view plain copy print?

  1. template <typename T>

  2. T& ObjectPool<T>::acquireObject()

  3. {

  4. if (mFreeList.empty()) {

  5. allocateChunk();

  6. }

  7. T* obj = mFreeList.front();

  8. mFreeList.pop();

  9. return (*obj);

  10. }

最后,releaseObject( ) 将对象返回到空闲列表的队尾。

[cpp] view plain copy print?

  1. template <typename T>

  2. void ObjectPool<T>::releaseObject(T& obj)

  3. {

  4. mFreeList.push(&obj);

  5. }

使用对象池

     请考虑一个要从用户得到请求并处理这些请求的应用。这个应用很可能是图形前端和后端数据库之间的一个中间件。例如,这可能是一个航空预定系统或一个在线银行应用的一部分。你可能想把每个用户请求编码到一个对象中,这个类可能如下。

[cpp] view plain copy print?

  1. class UserRequest

  2. {

  3. public:

  4. UserRequest() {}

  5. ~UserRequest() {}

  6. // Methods to populate the request with specific information.

  7. // Methods to retrieve the request data.

  8. // (not shown)

  9. protected:

  10. // data members (not shown)

  11. };

这里不用在程序的整个生命期中创建和删除大量请求,而是可以使用一个对象池。程序可能如下所示:

[cpp] view plain copy print?

  1. UserRequest& obtainUserRequest(ObjectPool<UserRequest>& pool)

  2. {

  3. // Obtain a UserRequest object from the pool

  4. UserRequest& request = pool.acquireObject();

  5. // populate the request with user input

  6. // (not shown)

  7. return (request);

  8. }

  9. void processUserRequest(ObjectPool<UserRequest>& pool, UserRequest& req)

  10. {

  11. // process the request

  12. // (not shown)

  13. // return the request to the pool

  14. pool.releaseObject(req);

  15. }

  16. int main(int argc, char** argv)

  17. {

  18. ObjectPool<UserRequest> requestPool(1000);

  19. // Set up program

  20. // (not shown)

  21. while (true /* program is running */) {

  22. UserRequest& req = obtainUserRequest(requestPool);

  23. processUserRequest(requestPool, req);

  24. }

  25. return (0);

  26. }

另外,,,使用线程池也是一个提高C++程序效率的不错方式。线程池和对象池很相似,即不在程序的整个生命期中动态地创建和删除线程,而是创建一个线程池,按需使用池中的线程。如果程序要处理到来的网络请求,这种程序中常常会用到这种技术.web 服务器就可以维护一个线程池,以备查找页面,从而对到来的各个客户请求作出反应。

转载自:

http://blog.csdn.net/chaoyuan899/article/details/9018197

转载于:https://blog.51cto.com/7044041/1856086

编写高效的C++程序方法之使用对象池相关推荐

  1. 如何编写高效优雅 Java 程序

    文章目录 编写高效优雅 Java 程序 面向对象 01.构造器参数太多怎么办? Builder 模式: 02.不需要实例化的类应该构造器私有 03.不要创建不必要的对象 04.避免使用终结方法 05. ...

  2. 【读书笔记】《编写高效的JavaScript程序》

    为什么80%的码农都做不了架构师?>>>    看到一篇文章,http://www.csdn.net/article/2012-11-20/2811887-writing-fast- ...

  3. 编写高效的JavaScript程序

    转载自http://kb.cnblogs.com/page/168162/ 英文原文:Writing Fast, Memory-Efficient JavaScript Addy Osmani是谷歌公 ...

  4. [实战分析] 编写高效的JavaScript程序

    摘要:有人说想要快速的加载Web网页就如同汽车一样,需要使用特殊工具.想知道JavaScript如何在V8中工作的吗?如何避免性能中出现的陷阱?当涉及到编写高效的内存和快速创建代码时总会出现一些常见的 ...

  5. 编写高效的C程序与C代码优化

    说明: 本篇文章翻译自:http://www.codeproject.com/Articles/6154/Writing-Efficient-C-and-C-Code-Optimization 其中参 ...

  6. 程序设计基石与实践系列之编写高效的C程序与C代码优化

    原文出处: codeproject:Writing Efficient C and C Code Optimization 虽然对于优化C代码有很多有效的指导方针,但是对于彻底地了解编译器和你工作的机 ...

  7. JVM性能调优5_编写高效优雅Java程序__享学课堂

    面向对象: ü 构造器参数太多怎么办(5个以上)? 使用构造者模式(build), package com.xiangxue.ch04.builder01;public class FoodBuild ...

  8. C++高级编程篇-如何编写高效的C++篇

    为了编写高效的程序,需要在设计层次上做考虑,并在实现层次上考虑细节.(一定要在程序的生命周期已开始就考虑性能). "编写高效的C++程序"指要编写能高效运行的程序,而不是高效地编写 ...

  9. Seastar:多核机器上编写高效复杂的服务器应用程序的 C++ 库

    目录 官网 联网 为什么选择网络替代品? 无共享设计 核心数量增长,时钟速度保持恒定 同时,I / O继续提高速度 海星模式:无共享 核心之间的明确通信 讯息传递 从程序员的角度 简化测试和故障排除 ...

最新文章

  1. 数据库对象 同义词 索引 序列 视图
  2. 【C++】Visual Studio教程(六) -更新Visual Studio
  3. 如何找到在SAP社区上经过SAP官方认可比较有影响力的SAP从业者
  4. 传统品牌vs新消费品牌社交营销差异化分析报告
  5. python socket文件传输
  6. 机器学习中训练集和测试集归一化(matlab版)
  7. 收藏十二:ExtJs
  8. KVM详解(三)——KVM创建虚拟机
  9. DDS原理以及MATLAB实现
  10. 基于BC95之AT命令的学习
  11. 微博舆情挖掘需求分析
  12. Python NLP 入门
  13. Hex Fiend——mac 下 WinHex的完美替代
  14. 如何为摇滚音乐选择吉他音箱,创作原创音乐
  15. 传音控股上海特性和功耗开发团队招期招聘优秀工程师啦
  16. AtCoder abc256全题解(区间合并模板、矩阵快速幂优化dp、线段树……)
  17. Mac电脑怎么关闭键盘的重复按键功能?
  18. SLAM在机器人中的应用
  19. 计算机关机符号不见了,笔记本电量图标不见了怎么修复?
  20. 足不出户买遍全球:亚马逊海外购启动史上最长“海外购物节”

热门文章

  1. Maven 项目中配置私服
  2. 英特尔再现安全漏洞:2011年后计算机几乎全中枪,可窃取你的密码及数据
  3. FIIL邬宁:AI能锦上添花,但耳机成不了下一个智能音箱
  4. 关于接口测试的一些总结
  5. 你从 Kotlin 中 get 了多少技能了?
  6. table height 100%问题
  7. Python Flask web后端开发
  8. fancybox 无效 失效 直接打开页面, ajax 之后 fancybox对更新的数据无效,Jquery失效 无效...
  9. Asp.net:DataList分页技术
  10. day2-安装python以及基本使用