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

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

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

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

5.总结

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

thinking in object pool的更多相关文章

  1. 设计模式之美:Object Pool(对象池)

    索引 意图 结构 参与者 适用性 效果 相关模式 实现 实现方式(一):实现 DatabaseConnectionPool 类. 实现方式(二):使用对象构造方法和预分配方式实现 ObjectPool ...

  2. Object Pool

    设计模式之美:Object Pool(对象池)   索引 意图 结构 参与者 适用性 效果 相关模式 实现 实现方式(一):实现 DatabaseConnectionPool 类. 意图 运用对象池化 ...

  3. .NET Core中Object Pool的简单使用

    前言 复用,是一个重要的话题,也是我们日常开发中经常遇到的,不可避免的问题. 举个最为简单,大家最为熟悉的例子,数据库连接池,就是复用数据库连接. 那么复用的意义在那里呢? 简单来说就是减少不必要的资 ...

  4. What are the differences between Flyweight and Object Pool patterns?

    What are the differences between Flyweight and Object Pool patterns? They differ in the way they are ...

  5. Object Pool 对象池的C++11使用(转)

    很多系统对资源的访问快捷性及可预测性有严格要求,列入包括网络连接.对象实例.线程和内存.而且还要求解决方案可扩展,能应付存在大量资源的情形. object pool针对特定类型的对象循环利用,这些对象 ...

  6. 对象池模式(Object Pool Pattern)

    本文节选自<设计模式就该这样学> 1 对象池模式的定义 对象池模式(Object Pool Pattern),是创建型设计模式的一种,将对象预先创建并初始化后放入对象池中,对象提供者就能利 ...

  7. Unity Object Pool完全体

    using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; public ...

  8. [译]Unity3D内存管理——对象池(Object Pool)

    原文地址:C# Memory Management for Unity Developers (part 3 of 3), 其实从原文标题可以看出,这是一系列文章中的第三篇,前两篇讲解了从C#语言本身 ...

  9. Java小对象的解决之道——对象池(Object Pool)的设计与应用

    一.概述 面向对象编程是软件开发中的一项利器,现已经成为大多数编程人员的编程思路.很多高级计算机语言也对这种编程模式提供了很好的支持,例如C++.Object Pascal.Java等.曾经有大量的软 ...

随机推荐

  1. OFM管理

    OMF:oracle management files 作用:不用指定文件的路径大小名字 OMF管理数据文件:db_create_file_dest 传统方式:SQL>create tables ...

  2. mysql(或者mariadb)连接工具HeidiSQL

    Some infos around HeidiSQL Project website: http://www.heidisql.com/Google Code: http://code.google. ...

  3. [C#] 與Android共舞–透過GET方式傳資料給Server(含解決中文編碼問題) (转帖)

    上一篇文章分享了透過POST 方式傳資料回Server,這一篇來談談有關於透過GET的方式傳遞 首先,如我預期的一樣,透過網址傳遞,會產生編碼問題,這邊我就順代解掉,希望有碰到的人 可以不用為此煩惱. ...

  4. PL/SQL 创建视图语法

    使用create view 语句创建视图 create [or replace][force | noforce] view [user.] viewName (column [,column2].. ...

  5. 高手速成android开源项目【导航篇】

    Android开发又将带来新一轮热潮,很多开发者都投入到这个浪潮中去了,创造了许许多多相当优秀的应用.其中也有许许多多的开发者提供了应用开源项目,贡献出他们的智慧和创造力.学习开源代码是掌握技术的一个 ...

  6. [C++] socket - 2 [UDP通信C/S实例]

    服务端: #include<iostream> #include<winsock2.h> #include<stdio.h> #pragma comment(lib ...

  7. 深入理解c++构造函数, 复制构造函数和赋值函数重载(operator=)

    注 以下代码编译及运行环境均为 Xcode 6.4, LLVM 6.1 with GNU++11 support, Mac OS X 10.10.2 调用时机 看例子 // // main.cpp / ...

  8. Spring简介和基础

    Spring介绍 1.什么事Spring? spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架. spring的设计模式是单例模式和工厂模式. 2.spring的四大优点 轻量 ...

  9. SSL在https和MySQL中的原理思考

    之前对HTTPS通信过程有过了解,HTTPS是应用HTTP协议使用SSL加密的版本,在TCP和HTTP之间增加SSL协议.通过握手阶段认证双方身份,协商对称秘钥对通信信息进行加密.此处只描述常用的服务 ...

  10. Leetcode 328 Odd Even Linked List 链表

    Given 1->2->3->4->5->NULL, return 1->3->5->2->4->NULL. 就是将序号为单数的放在前面,而 ...