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等.曾经有大量的软 ...
随机推荐
- OFM管理
OMF:oracle management files 作用:不用指定文件的路径大小名字 OMF管理数据文件:db_create_file_dest 传统方式:SQL>create tables ...
- mysql(或者mariadb)连接工具HeidiSQL
Some infos around HeidiSQL Project website: http://www.heidisql.com/Google Code: http://code.google. ...
- [C#] 與Android共舞–透過GET方式傳資料給Server(含解決中文編碼問題) (转帖)
上一篇文章分享了透過POST 方式傳資料回Server,這一篇來談談有關於透過GET的方式傳遞 首先,如我預期的一樣,透過網址傳遞,會產生編碼問題,這邊我就順代解掉,希望有碰到的人 可以不用為此煩惱. ...
- PL/SQL 创建视图语法
使用create view 语句创建视图 create [or replace][force | noforce] view [user.] viewName (column [,column2].. ...
- 高手速成android开源项目【导航篇】
Android开发又将带来新一轮热潮,很多开发者都投入到这个浪潮中去了,创造了许许多多相当优秀的应用.其中也有许许多多的开发者提供了应用开源项目,贡献出他们的智慧和创造力.学习开源代码是掌握技术的一个 ...
- [C++] socket - 2 [UDP通信C/S实例]
服务端: #include<iostream> #include<winsock2.h> #include<stdio.h> #pragma comment(lib ...
- 深入理解c++构造函数, 复制构造函数和赋值函数重载(operator=)
注 以下代码编译及运行环境均为 Xcode 6.4, LLVM 6.1 with GNU++11 support, Mac OS X 10.10.2 调用时机 看例子 // // main.cpp / ...
- Spring简介和基础
Spring介绍 1.什么事Spring? spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架. spring的设计模式是单例模式和工厂模式. 2.spring的四大优点 轻量 ...
- SSL在https和MySQL中的原理思考
之前对HTTPS通信过程有过了解,HTTPS是应用HTTP协议使用SSL加密的版本,在TCP和HTTP之间增加SSL协议.通过握手阶段认证双方身份,协商对称秘钥对通信信息进行加密.此处只描述常用的服务 ...
- Leetcode 328 Odd Even Linked List 链表
Given 1->2->3->4->5->NULL, return 1->3->5->2->4->NULL. 就是将序号为单数的放在前面,而 ...