当前位置: 首页 > news >正文

智能指针之设计模式3

这次我们看一下智能指针是如何使用策略模式来释放资源的,同时又是如何扩展功能,管理更多的资源对象类型的。

3、策略模式

策略模式作为一种软件设计模式,指对象有某个行为,但是在不同的应用场景中,该行为有不同的实现算法。它的意图是:定义一系列算法,把它们一个个封装起来,并且使它们可相互替换,算法可独立于使用它的客户而变化。

下面是它的结构图:
在这里插入图片描述
组成结构:
—Stragety(抽象策略角色): 策略类,定义算法的公共接口。
—ConcreteStragety(具体策略角色):具体策略类,实现某种具体算法。
—Context(环境上下文角色):持有一个策略类的引用,最终给客户端调用。

本质上就是在C++中,一个Stragety基类定义了虚函数(即算法),它的不同ConcreteStragety派生类重写了虚函数的实现,而Context类中有一个Stragety引用类型的数据成员,可以存放不同的派生类对象,它可以调用基类数据成员的虚函数,并不知道数据成员的实际类型,显然这是面向对象动态绑定机制,这样各个派生类ConcreteStragety对象可以互相替换,不会对Context有任何影响。

我们看一下智能指针的删除器,它的功能是为智能指针提供释放资源的方法,有不同的形式和类型,智能指针会在它的reset()成员函数和析构函数中调用删除器,也不关心是什么形式的删除器,只要能调用它的void operator()(T *ptr)操作符就行。

我们再次脑洞大开一下,把一个提供了形如void operator()(T *ptr)调用操作符的函数对象类看作是策略基类,它定义了具体策略类所要实现的接口功能。如同上一篇文章中使用面向对象技术把指针封装成一个类一样,同样,现在也把删除器封装成一个函数对象类,作为抽象策略基类。如下所示:

class deleter {
public:void operator()(T *ptr);
}

该类对象的核心功能是:void operator()(T *ptr),等同于策略模式中的算法,供智能指针对象调用来销毁资源对象,只要一个类提供了参数是指针类型没有返回值的可调用操作符,都可以算作是它的派生类。

显然,对于普通函数:

void deleter_func(T *ptr) {delete ptr;
}

函数对象:

class deleter_func_obj {
public:void operator()(T *ptr) {delete ptr;}
}

lambda表达式:

auto deleter_lambda = [](T *ptr) {delete ptr};

以及function对象:

function<void(T *ptr)> func = bind(xxxx);

它们都提供了符合要求的可调用对象的函数接口,用面向对象术语的话,可以说它们都是deleter类的派生类,它们都被看作是具体的策略类对象,提供了不同的算法。那么在创建unique_ptr或者shared_ptr对象时,均可以选择一个作为参数传入,它们是可以互相替换的。显然,这正是策略模式背后所体现的思想,可以让智能指针灵活地支持多种类型的删除器,在这里,智能指针unique_ptr和shared_ptr对应了context环境角色,而删除器deleter对应了stragety策略角色。

这种模式的好处:

首先,可以使用不同形式的删除器。
显然,可以使用函数指针、函数对象、lambda表达式,以及function对象等不同形式来创建deleter对象,不管它们的外在形式如何,只要实现了void (T *ptr)方法,都可以在创建智能指针时选择一个作为策略对象传入,在需要的时候调用它们。

其次,可以扩展智能指针的功能。
策略模式中,可以把context角色类比为一个基类对象,而strategy角色就是派生类对象要实现的虚函数,只不过不是通过继承基类来实现虚函数功能,而是把要实现的虚函数封装成strategy对象,然后传入contex中去回调,显然这样也等同于使用不同的stragety扩展了context的不同功能。

我们知道,智能指针可以管理不同形式的资源,资源对象可以是数组,可以是普通对象、可以来自堆中,可以来自栈中,在释放时,有的需要使用delete操作符,有的需要使用free()函数,有的需要使用close()函数。比如unique_ptr类,它是C++标准库提供的类型,无法修改它的源码,它是怎样做到能够管理更多的资源的?

看一下deleter角色,它的接口需要一个参数T *ptr,这个参数就是智能指针对象所管理的资源对象,在调用deleter时由智能指针作为参数传入ptr。因此,deleter知道ptr的一切信息,完全可以使用ptr做一些具体的算法逻辑操作,相当于扩展了智能指针对象的功能:只要deleter对象根据参数类型实现不同的功能,智能指针又调用deleter,不就是它实现了该功能吗。

传入不同的deleter对象,也等同于扩展了智能指针的不同功能。这样,智能指针不但可以管理内存资源,而且可以管理句柄、socket、文件指针、文件描述符等其它形式的资源。

下面一个演示,通过lambda表达式实现了关闭文件指针的操作,unique_ptr使用它扩展了自己的功能:也可以管理FILE文件指针资源了。

FILE *file = fopen("/tmp/tmp.txt", "r"); // 分配FILE资源
unique_ptr<FILE, void(*)(FILE *)> fup(file, [](FILE *file) {fclose(file);
});

相关文章:

  • 如何使用 Spring Boot 实现统一功能处理:从零开始打造高效、可扩展的后台系统
  • 31Calico网络插件的简单使用
  • 常用python爬虫框架介绍
  • 测试第四课---------性能测试工具
  • gbase8s触发器使用
  • 使用 LangChain + Higress + Elasticsearch 构建 RAG 应用
  • Python 获取淘宝买家订单列表(buyer_order_list)接口的详细指南
  • 【C++】新手入门指南(下)
  • 建造者模式详解及其在自动驾驶场景的应用举例(以C++代码实现)
  • C++(初阶)(十二)——stack和queue
  • container_memory_working_set_bytes` 与 `container_memory_usage_bytes` 的区别
  • C++ 学习指南
  • Redis 处理读请求
  • 安全文件共享实际上是什么样的呢?
  • 解决找不到字体的问题
  • windows搭建xwiki17服务器
  • [Java · 铢积寸累] 数据结构 — 数组类型 - Arrays 工具类详解
  • 稳定PCDN运营效率
  • 【leetcode100】零钱兑换Ⅱ
  • 物联网赋能玻璃制造业:实现设备智能管理与生产协同
  • 美国国务院:鲁比奥将不参加在伦敦举行的乌克兰问题会谈
  • 2024年我国数字阅读用户规模达6.7亿
  • 坚守17年,这件事姚明就算赔钱也在继续做
  • 对话地铁读书人|豪宅房产经纪人:读书使我免于抑郁
  • 浙江一季度GDP为22300亿元,同比增长6.0%
  • 第八届进博会将致力于打造“五个高”,为展商增值赋能