thinking in object pool
1.背景
对象池为了避免频繁创建耗时或耗资源的大对象,事先在对象池中创建好一定数量的大对象,然后尽量复用对象池中的对象,用户用完大对象之后放回对象池。
2.问题
目前纵观主流语言的实现方式无外乎3个步骤:
- 初始创建一定数量的对象池(也允许从外面添加对象)。
- 从对象池中取对象来使用。
- 用完之后返回对象池。
一般情况下这样是OK的,可能存在的问题是在第三步,有两个问题:
- 不方便,每次都需要显式回收对象。
- 忘记将对象放回对象池,造成资源浪费。
3.改进动机
解决显式回收的问题,实现自动回收,省心省力。
4.技术内幕
借助c++智能指针,因为智能指针可以自定义删除器,在智能指针释放的时候会调用删除器,在删除器中我们将用完的对象重新放回对象池。思路比较简单,但实现的时候需要考虑两个问题:
- 什么时候定义删除器?
- 用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的更多相关文章
- 设计模式之美:Object Pool(对象池)
索引 意图 结构 参与者 适用性 效果 相关模式 实现 实现方式(一):实现 DatabaseConnectionPool 类. 实现方式(二):使用对象构造方法和预分配方式实现 ObjectPool ...
- Object Pool
设计模式之美:Object Pool(对象池) 索引 意图 结构 参与者 适用性 效果 相关模式 实现 实现方式(一):实现 DatabaseConnectionPool 类. 意图 运用对象池化 ...
- .NET Core中Object Pool的简单使用
前言 复用,是一个重要的话题,也是我们日常开发中经常遇到的,不可避免的问题. 举个最为简单,大家最为熟悉的例子,数据库连接池,就是复用数据库连接. 那么复用的意义在那里呢? 简单来说就是减少不必要的资 ...
- 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 ...
- Object Pool 对象池的C++11使用(转)
很多系统对资源的访问快捷性及可预测性有严格要求,列入包括网络连接.对象实例.线程和内存.而且还要求解决方案可扩展,能应付存在大量资源的情形. object pool针对特定类型的对象循环利用,这些对象 ...
- 对象池模式(Object Pool Pattern)
本文节选自<设计模式就该这样学> 1 对象池模式的定义 对象池模式(Object Pool Pattern),是创建型设计模式的一种,将对象预先创建并初始化后放入对象池中,对象提供者就能利 ...
- Unity Object Pool完全体
using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; public ...
- [译]Unity3D内存管理——对象池(Object Pool)
原文地址:C# Memory Management for Unity Developers (part 3 of 3), 其实从原文标题可以看出,这是一系列文章中的第三篇,前两篇讲解了从C#语言本身 ...
- Java小对象的解决之道——对象池(Object Pool)的设计与应用
一.概述 面向对象编程是软件开发中的一项利器,现已经成为大多数编程人员的编程思路.很多高级计算机语言也对这种编程模式提供了很好的支持,例如C++.Object Pascal.Java等.曾经有大量的软 ...
随机推荐
- QQ摄像头读取条码
跟我学机器视觉-HALCON学习例程中文详解-QQ摄像头读取条码 第一步:插入QQ摄像头,安装好驱动(有的可能免驱动) 第二步:打开HDevelop,点击助手—打开新的Image Acquisitio ...
- sqlplus实现上下翻页设置
环境: 操作系统:red hat 5.8 OS 数据库:oracle 11g 11.2.0.1 安装软件:IO-Tty-1.07.tar. Term-ReadLine-Gnu-1.16.tar.uni ...
- sql trunc()的使用
1.TRUNC(for dates)TRUNC函数为指定元素而截去的日期值.其具体的语法格式如下:TRUNC(date[,fmt])其中:date 一个日期值fmt 日期格式,该日期将由指定的元素格式 ...
- 【Leetcode】【Hard】Merge Intervals
Given a collection of intervals, merge all overlapping intervals. For example,Given [1,3],[2,6],[8,1 ...
- Reading Notes of Acceptance Test Engineering Guide
The Acceptance Test Engineering Guide will provide guidance for technology stakeholders (developers, ...
- [ACM_数据结构] 竞赛排名
比赛排名 Time Limit:1000MS Memory Limit:32768K Description: 欢迎参加浙江工业大学“亚信联创杯”程序设计大赛,本次竞赛采用与 ACM/ICPC 相同 ...
- [ACM_图论] Highways (变形说法的最小生成树)
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=28972#problem/C 题目给出T种情况,每种情况有n个城镇,接下来每一行是第i个城 ...
- [matlab] 矩阵操作
>_<:矩阵构造 1.简单矩阵构造 最简单的方法是采用矩阵构造符“[]”.构造1´n矩阵(行向量)时,可以将各元素依次放入矩阵构造符[]内,并且以空格或者逗号分隔:构造m´n矩阵时,每行如 ...
- ActiveMQ第五弹:增加ReDelivery功能
在使用Message Queue的过程中,总会由于种种原因而导致消息失败.一个经典的场景是一个生成者向Queue中发消息,里面包含了一组邮件地址和邮件内容.而消费者从Queue中将消息一条条读出来,向 ...
- 【仅支持移动设备】Swipe.JS轻量级移动幻灯效果
在线演示 本地下载 请使用手机直接访问地址: 单独页面展示效果