OpenHarmony 实战开发——智能指针管理动态分配内存对象

概述

智能指针是行为类似指针的类,在模拟指针功能的同时提供增强特性,如针对具有动态分配内存对象的自动内存管理等。

  • 自动内存管理主要是指对超出生命周期的对象正确并自动地释放其内存空间,以避免出现内存泄漏等相关内存问题。
  • 智能指针对每一个RefBase对象具有两种不同的引用形式。强引用持有对一个对象的直接引用。 具有强引用关系的对象在该强引用关系存在时同样也应当存在,也即该引用关系有效;弱引用持有对一个对象的间接引用。 具有弱引用关系的对象在该弱引用关系存在时并不保证存在。

注意:上述描述仅当正确使用智能指针时才成立。

实现原理

  • 智能指针通过引用计数来实现所指向对象内存的自动管理。每一个可以被智能指针管理的对象都持有一个引用计数器,引用计数器在相关引用计数清0时会调用一个用于销毁该对象的回调函数。

  • 引用计数器记录了对应RefBase对象的两种不同引用计数值,以及对于其本身,即RefCounter对象的引用计数值。

涉及功能

OHOS::sptr

模块: SmartPointer

指向RefBase(或其子类)对象的强引用智能指针。

具体描述
template <typename T >
class OHOS::sptr;

指向RefBase(或其子类)对象的强引用智能指针。

模板参数:

  • T 被sptr管理的具体类型。该类必须继承自RefBase基类。

其直接引用RefBase对象。

#include <refbase.h>

接口说明

OHOS::wptr

模块: SmartPointer

指向RefBase(或其子类)对象的弱引用智能指针。

具体描述
template <typename T >
class OHOS::wptr;

指向RefBase(或其子类)对象的弱引用智能指针。

模板参数:

  • T 被wptr管理的具体类型。该类必须继承自RefBase基类。

其间接引用RefBase对象;直接引用WeakRefCounter对象。

#include <refbase.h>

接口说明

使用示例

  1. 使用方法(伪代码)
#include "../include/refbase.h"
#include <iostream>

using namespace std;
using namespace OHOS;

// 管理目标类
class RefBaseTest : public RefBase {
public:
    virtual void Access()
    {
        cout<<"Access RefBaseTest::Show"<<endl;
    }

    ~RefBaseTest() override
    {
        cout << "RefBaseTest destroyed" << endl;
    }
};

// 管理目标类的子类
class SubRefBaseTest : public RefBaseTest {
public:
    void Access() override
    {
        cout<<"Access SubRefBaseTest::Show"<<endl;
    }

    ~SubRefBaseTest() override
    {
        cout << "SubRefBaseTest destroyed" << endl;
    }
};

int main()
{
    // 1. 使用新创建智能指针,管理新创建对象
    sptr<RefBaseTest> newSptr(new RefBaseTest());
    wptr<RefBaseTest> newWptr(new RefBaseTest());

    // 2. 使用上述智能指针,管理另一个新创建对象
    // 原管理对象析构
    newSptr = new RefBaseTest();
    newWptr = new RefBaseTest();

    // 3. 使用新创建智能指针,指向其他现存智能指针管理对象
    sptr<RefBaseTest> curSptr(newSptr);
    wptr<RefBaseTest> curWptr(newWptr);

    if (curSptr->GetSptrRefCount() == 2 && curSptr->GetWptrRefCount() == 2 && // 2: count
       curWptr->GetWptrRefCount() == 1) {
        cout << "curSptr run as expected" << endl;
    }

    // 4. 使用现存智能指针管理其托管类型的子类对象
    sptr<SubRefBaseTest> subSptr(new SubRefBaseTest());
    wptr<SubRefBaseTest> subWptr(new SubRefBaseTest());

    curSptr = subSptr;
    curWptr = subWptr;

    // 5. 通过->运算符访问成员"
    curSptr->Access();
    curWptr->Access();

    // 6. 通过*运算符解引用
    (*curSptr).Access();
    (*curSptr).Access();

    // 7. 两种智能指针可以管理对方所管理的对象
    sptr<RefBaseTest> scurSptr(new RefBaseTest);
    wptr<RefBaseTest> scurWptr(new RefBaseTest);

    wptr<RefBaseTest> snewWptr(scurSptr);

    sptr<RefBaseTest> soldSptr(new RefBaseTest);
    wptr<RefBaseTest> soldWptr(new RefBaseTest);
    soldSptr = scurWptr; // sptr仅可通过拷贝赋值管理wptr所管理对象
    soldWptr = scurSptr; // 原本的引用关系将被释放

    if (snewWptr->GetWptrRefCount() == 3 && soldSptr->GetSptrRefCount() == 1 && // 3: count
        soldWptr->GetWptrRefCount() == 3) { // 3: count
            cout << "Smart Pointer assignment run as expected" << endl;
        }
    // 8. wptr可升级为sptr
    sptr<RefBaseTest> spromotedWptr = snewWptr.promote(); // 升级失败时返回空sptr对象,即未管理具体对象的sptr对象
    if (spromotedWptr->GetSptrRefCount() == 2 && spromotedWptr->GetWptrRefCount() == 4) { // 2, 4: count
        cout << "Promote run as expected" << endl;
    }

    return 0;
}
  1. 测试用例编译运行方法
  • 测试用例代码参见 base/test/unittest/common/utils_refbase_test.cpp

  • 使用开发者自测试框架,使用方法参见: 开发自测试执行框架-测试用例执行

  • 使用以下具体命令以运行refbase.h对应测试用例

run -t UT -tp utils -ts UtilsRefBaseTest
  1. debug功能 RefTracker作为debug工具被添加入refbase文件中,以便开发者对RefBase相关问题进行定位。该功能需要重新编译动态库替换系统原有动态库来上机使用(如是静态依赖则需开发者独立审视使能方法)。
  • 全局追踪

全局追踪功能通过编译宏控制,可以追踪全局的RefBase及其子类的轨迹,但同时会对整机性能造成影响。 全局追踪中我们提供了立即打印模式及非立即打印模式。立即打印模式会在每次引用计数发生变化时对计数进行打印。非立即打印模式会在RefBase及其子类对象析构时对轨迹进行打印。

全局追踪、立即打印编译命令:

./build.sh --product-name xxx --ccache --build-target commonlibrary/c_utils/base:utils --gn-args c_utils_debug_refbase=true --gn-args c_utils_track_all=true --gn-args c_utils_print_track_at_once=true

全局追踪、非立即打印编译命令:

./build.sh --product-name xxx --ccache --build-target commonlibrary/c_utils/base:utils --gn-args c_utils_debug_refbase=true --gn-args c_utils_track_all=true
  • 独立追踪

独立追踪功能同样能通过编译宏控制。我们为开发者提供了RefBase::EnableTracker()接口来对某个具体实例使能追踪功能。独立追踪对性能影响很小,可以忽略不计。在独立追踪中我们能同样提供了立即打印及非立即打印模式。

独立追踪、立即打印编译命令:

./build.sh --product-name xxx --ccache --build-target commonlibrary/c_utils/base:utils --gn-args c_utils_debug_refbase=true --gn-args c_utils_print_track_at_once=true

独立追踪、非立即打印编译命令:

./build.sh --product-name xxx --ccache --build-target commonlibrary/c_utils/base:utils --gn-args c_utils_debug_refbase=true
  • 使用方法

编译动态库,编译产物路径为./out/xxx/commonlibrary/c_utils/libutils.z.so

编译产物需要推入系统进行替换,64位系统位于/system/lib64/,32位系统位于/system/lib/

追踪结果通过log打印。格式如下:

// 立即打印
(sptr pointer) start tracking
(sptr pointer) call (RefBase pointer). strong: x weak: x refcnnt: x
...
(sptr pointer) call (RefBase pointer). strong: x weak: x refcnnt: x
(sptr pointer) end tracking

// 非立即打印
(sptr pointer) start backtrace
(sptr pointer) call (RefBase pointer). strong: x weak: x refcnnt: x PID: xxx TID: xxx
...
(sptr pointer) call (RefBase pointer). strong: x weak: x refcnnt: x PID: xxx TID: xxx
(sptr pointer) end backtrace

常见问题

  1. 使用本实现智能指针时,同时使用裸指针或std标准库智能指针(std::shared_ptr)

    • 会造成管理冲突,导致非法访问以及未定义行为,如内存重复释放。
      • 因此也不推荐先创建裸指针后,再使用智能指针管理。
RefBase* a = new RefBase();
sptr<RefBase> s = a;
// 或
sptr<RefBase> s(a); // 裸指针a容易被误delete,造成sptr功能失常
  1. 智能指针需构造在栈上,管理的对象需要在堆上(动态分配对象)

    • 智能指针若构造在堆上则不符合定义。
    • 管理对象若构造在栈上,则会自动释放,错误绕开智能指针管控。
  2. 智能指针不保证线程安全,使用者需保证线程安全以避免同时对同一个sptr对象赋值等操作

  3. 避免通过隐式转换构造智能指针对象

    • 易造成误解。
    • 因编译器优化程度具有不确定的行为,易造成问题。
  4. 不建议使用对象指针构造智能指针对象

    • 外部提前以指针形式释放对象后,继续通过智能指针中使用
    • sptr引用计数为0释放对象,对象指针依旧在外被继续使用
Refbase *a = new Refbase(arg1, arg2);
sptr<Refbase> sp1 = a; // 不建议,对象指针a暴露在外,存在风险
sptr<Refbase> sp2(a); // 不建议,对象指针a暴露在外,存在风险
sptr<Refbase> sp3 = sptr<Refbase>::MakeSptr(arg1, arg2); // 建议,在内部构造Refbase对象,直接交与sptr管控使用
  1. wptr使用注意

    • 在未设置ExtendObjectLifetime的情况下,wptr不参与被管理对象的生命周期控制,对象生命周期由sptr的引用计数控制,但在极特殊情况下存在例外
// 由于历史设计原因,可以在sptr不存在的情况下,基于对象指针创建wptr对象。
// 在未设置ExtendObjectLifetime,且无sptr被创建的特殊少见情况下,为了防止内存泄漏,在wptr引用计数归0时会释放管理对象
Refbase *a = new Refbase(arg1, arg2);
wptr<Refbase> wp1(a);
wp1 = nullptr; // 弱引用计数归0,对象释放,应避免再次手动释放

wptr<Refbase> wp2 = new Refbase(arg1, arg2);
wp2 = nullptr; // 弱引用计数归0,对象释放,这种情况无法手动释放, 如果wptr不能控制对象释放则必然会发生内存泄漏

写在最后

  • 如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  • 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
  • 想要获取更多完整鸿蒙最新学习资源,请移步前往小编:https://gitee.com/MNxiaona/733GH

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/586288.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

docker学习笔记4:CentOS7安装docker

文章目录 一、安装docker二、配置阿里云加速三、测试镜像安装本篇博客介绍如何在centos7里安装docker,关于CentOS7的安装可以查看本专栏的这篇博客: VmWare CentOS7安装与静态ip配置 centos7里安装docker步骤如下: 一、安装docker 先在终端输入su进入root用户,输入如下命…

linux 服务器利用阿里网盘API实现文件的上传和下载

文章目录 背景脚本初始化 阿里云盘API工具 aligo安装aligoaligo教程实战parse.py 演示上传文件上传文件夹下载文件下载文件夹 背景 最近在用ubuntu系统做实验&#xff0c;而ubuntu 系统的文件上传和下载操作很麻烦&#xff1b; 于是便打算使用阿里网盘的API 进行文件下载与上传…

ChatGPT 网络安全秘籍(四)

原文&#xff1a;zh.annas-archive.org/md5/6b2705e0d6d24d8c113752f67b42d7d8 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 第八章&#xff1a;事故响应 事故响应是任何网络安全策略的关键组成部分&#xff0c;涉及确定、分析和缓解安全漏洞或攻击。 及时和有效地…

推荐一个wordpress免费模板下载

首页大背景图&#xff0c;首屏2张轮播图&#xff0c;轮换展示&#xff0c;效果非常的炫酷&#xff0c;非常的哇噻&#xff0c;使用这个主题搭建的wordpress网站&#xff0c;超过了200个&#xff0c;虽然是一个老主题了&#xff0c;不过是经得起时间考验的&#xff0c;现在用起来…

IDEA 中 git fetch 验证报错 The provided password or token is incorrect

参考链接&#xff1a; 【GitLab】-HTTP Basic: Access denied.remote:You must use a personal access token_http basic: access denied. the provided password o-CSDN博客 idea使用gitLab报错&#xff1a;remote: HTTP Basic: Access denied_idea remote: http basic: acc…

C++编译器的程序转化

编译器在某些情况下会对程序进行转化&#xff0c;有些是编译器需要的&#xff0c;有些是出于性能考虑的&#xff0c;转化可能会产生出乎意料的结果 文章目录 明确的初始化操作参数的初始化返回值的初始化在使用者层面做优化在编译器层面做优化NRV 优化NRV优化的弊端 明确的初始…

在AndroidStudio创建Flutter项目并运行到模拟器

1.Flutter简介 Flutter是Google开源的构建用户界面&#xff08;UI&#xff09;工具包&#xff0c;帮助开发者通过一套代码库高效构建多平台精美应用&#xff0c;支持移动、Web、桌面和嵌入式平台。Flutter 开源、免费&#xff0c;拥有宽松的开源协议&#xff0c;适合商…

基于模糊PI控制算法的龙格库塔CSTR模型控制系统simulink建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 5.完整工程文件 1.课题概述 基于模糊PI控制算法的龙格库塔CSTR模型控制系统simulink建模与仿真。基于模糊PI控制算法的龙格-库塔&#xff08;Runge-Kutta, RK&#xff09;连续搅拌釜反应器&#xff08;Co…

C语言.自定义类型:结构体

自定义类型&#xff1a;结构体 1.结构体类型的声明1.1结构体回顾1.1.1结构体的声明1.1.2结构体变量的创建和初始化 1.2结构体的特殊声明1.3结构体的自引用 2.结构体内存对齐2.1对齐规则2.2为什么存在内存对齐2.3修改默认对齐数 3.结构体传参4.结构体实现位段4.1什么是位段4.2位…

[附源码]SpringBoot+Vue网盘项目_仿某度盘

视频演示 [附源码]SpringBootVue网盘项目_仿某度盘 功能介绍 支持秒传支持视频音频播放、拖拽进度条、倍速播放等支持图片预览&#xff0c;旋转&#xff0c;放大支持多人一起上传&#xff0c;共享上传进度&#xff08;例如a上传苍老师学习资料到50%&#xff0c;突然b也上传苍老…

PHP源码_最新Ai对话系统网站源码 ChatGPT+搭建教程+前后端

基于ChatGPT开发的一个人工智能技术驱动的自然语言处理工具&#xff0c;它能够通过学习和理解人类的语言来进行对话&#xff0c;还能根据聊天的上下文进行互动&#xff0c;真正像人类一样来聊天交流&#xff0c;甚至能完成撰写邮件、视频脚本、文案、翻译、代码&#xff0c;写论…

【MySQL精炼宝库】深度解析索引 | 事务

目录 一、索引 1.1 索引(index)概念&#xff1a; 1.2 索引的作用&#xff1a; 1.3 索引的缺点&#xff1a; 1.4 索引的使用场景&#xff1a; 1.5 索引的使用&#xff1a; 1.6 面试题:索引底层的数据结构&#xff08;核心内容&#xff09;&#xff1a; 1.7 索引列查询(主…

【opencv4.8.1 源码编译】windows10 OpenCV 4.8.1源码编译并实现 CUDA 12加速

Windows 下使用 CMake3.29.2 Visual Studio 2022 编译 OpenCV 4.8.1 及其扩展模块cuda12.0teslaT4显卡 记录自己在编译时踩过的坑&#xff0c;避免下次再犯或者给有需要的人。 在实际使用中&#xff0c;如果是对处理时间要求比较高的场景&#xff0c;使用OpenCV处理图片数据很…

Flask教程2:flask高级视图

文章目录 add_url_rule类视图的引入装饰器的自定义与使用蓝图的使用url_prefix设置蓝图前缀 add_url_rule 欲实现url与视图函数的绑定&#xff0c;除了使用路由装饰器app.route&#xff0c;我们还可以通过add_url_rule(rule,endpointNone,view_funcNone)方法&#xff0c;其中&…

Flutter笔记:Widgets Easier组件库(1)使用各式边框

Flutter笔记 Widgets Easier组件库&#xff08;1&#xff09;&#xff1a;使用边框 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress o…

【stomp 实战】Spring websocket 用户订阅和会话的管理源码分析

通过Spring websocket 用户校验和业务会话绑定我们学会了如何将业务会话绑定到spring websocket会话上。通过这一节&#xff0c;我们来分析一下会话和订阅的实现 用户会话的数据结构 SessionInfo 用户会话 用户会话定义如下&#xff1a; private static final class Sessio…

利用Argo数据分别计算温度、盐度和温盐所造成的比容海平面变化

本文所用到的温盐数据集&#xff1a;IPRC&#xff08;美国夏威夷大学国际太平洋研究中心&#xff09; Argo data products | Argo (ucsd.edu)https://argo.ucsd.edu/data/argo-data-products/ 理论知识&#xff08;相关计算公式&#xff09;&#xff1a; 代码和工具包准备&…

python 中的数据结构

python 中的数据结构 1.1 序列 序列时有索引的数组 举例实现&#xff1a; a["北京","上海","广州","深圳","重庆","成都"] print(a[2]) print(a[-1] " " a[-2]) print(a[1:3]) # 运行结果 "&…

Vulnhub-DIGITALWORLD.LOCAL: VENGEANCE渗透

文章目录 前言1、靶机ip配置2、渗透目标3、渗透概括 开始实战一、信息获取二、smb下载线索三、制作字典四、爆破压缩包密码五、线索分析六、提权&#xff01;&#xff01;&#xff01; Vulnhub靶机&#xff1a;DIGITALWORLD.LOCAL: VENGEANCE ( digitalworld.local: VENGEANCE …

chrome和drive安装包路径

Chrome for Testing availability (googlechromelabs.github.io) 下载Stable下面的包哈
最新文章