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

【Orange Pi 5嵌入式C语言编程】-智能指针简单实现

智能指针简单实现

文章目录

  • 智能指针简单实现
    • 1、实现变量自动清理
    • 2、内存管理析构函数实现
    • 3、小结

我们知道,在C语言中,对内存进行管理是一件非常麻烦的事情,一不小心就可能出现内存泄露或导致一些不可知道的错误。本文将详细介绍如何利用GCC编译器的特性来实现一个C语言智能指针。

1、实现变量自动清理

在GCC中,可以通过cleanup属性来实现变量进行自动清理。只需创建某种可能的类型属性,以使变量在超出范围后释放自身:

#define autofree __attribute__((cleanup(free_stack)))
__attribute__ ((always_inline))
inline void free_stack(void *ptr) {free(*(void **) ptr);printf("cleanup done\n");
}

用法非常简单:

// cleanup.c
int main(int argc, char** argv) {printf("hello world,auto clean up\n");autofree int *i = malloc(sizeof (int));*i = 1;return 0;
}

编译并运行:

gcc -o cleanup cleanup.c

输出如下:

hello world,auto clean up
cleanup

2、内存管理析构函数实现

在前面的变量自动清理方法在简单的变量内存管理中效果比较好。在实际应用中,我们知道大多数动态分配的数据都是复杂的数据,具有(也是动态分配的)成员 ,并且由于无法在结构成员上添加清理属性,因此有必要引入某种**析构函数机制**。

在这里,我们在分配的内存中添加一些元数据 - 这应该是实现新目标的最非侵入性的方式:

在这里插入图片描述

我们将使用两个函数:一个用于分配内存,另一个用于释放内存。

/*** @brief 内存分配函数* @param size 内存分配大小* @param dtor 析构函数
*/
__attribute__((malloc))
void* smalloc(size_t size, void (*dtor)(void*)) {struct meta* meta = malloc(sizeof(struct meta) + size);*meta = (struct meta){.dtor = dtor,.ptr = meta + 1};return meta->ptr;
}/*** @brief 内存释放函数* @param ptr 需要释放的内存对象
*/
void sfree(void* ptr) {if (ptr == NULL)return;struct meta* meta = get_meta(ptr);assert(ptr == meta->ptr); // ptr shall be a pointer returned by smallocmeta->dtor(ptr);free(meta);
}

这两个函数都非常简单:smalloc 分配内存来托管请求的数据大小和我们需要的元数据。 然后,它初始化所述元数据并存储析构函数,并将指针返回到未初始化的用户数据的开头。

sfree 的行为与 free 完全相同,因为如果传递 NULL,它不会执行任何操作,否则会释放内存。 唯一的区别是,它在实际释放之前调用在调用smalloc期间存储的析构函数,以便可以执行清理步骤。

#define smart __attribute__((cleanup(sfree_stack)))
__attribute__ ((always_inline))
inline void sfree_stack(void *ptr) {sfree(*(void **) ptr);
}

sfree 运行析构函数的直接后果之一是 sfree 是通用释放器,类似于 C++ 中的 delete 关键字。

这意味着对于smalloc管理的任何类型,我们都可以对其调用 sfree,而不必担心真正的析构函数,而且我知道它会被销毁 - 这是一个巨大的改进。

使用示例如下:

// smalloc.c#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>#define autofree __attribute__((cleanup(free_stack)))
__attribute__((always_inline))
inline void free_stack(void* ptr) {printf("cleanup\n");free(*(void**)ptr);
}struct meta {void (*dtor)(void*);void* ptr;
};static struct meta* get_meta(void* ptr) {return ptr - sizeof(struct meta);
}/*** @brief 内存分配函数* @param size 内存分配大小* @param dtor 析构函数
*/
__attribute__((malloc))
void* smalloc(size_t size, void (*dtor)(void*)) {struct meta* meta = malloc(sizeof(struct meta) + size);*meta = (struct meta){.dtor = dtor,.ptr = meta + 1};return meta->ptr;
}/*** @brief 内存释放函数* @param ptr 需要释放的内存对象
*/
void sfree(void* ptr) {if (ptr == NULL)return;struct meta* meta = get_meta(ptr);assert(ptr == meta->ptr); // ptr shall be a pointer returned by smallocmeta->dtor(ptr);free(meta);
}#define smart __attribute__((cleanup(sfree_stack)))
__attribute__((always_inline))
inline void sfree_stack(void* ptr) {sfree(*(void**)ptr);
}
typedef struct _values {int key;int32_t* int_values;
}values_t;typedef struct {uint8_t* datas;values_t* values;
}complex_data_t;void complex_data_free(complex_data_t* data) {if (data == NULL) {return;}if (data->values) {if (data->values->int_values) {free(data->values->int_values);data->values->int_values = NULL;printf("complex_data_free:free int_values done\n");}free(data->values);data->values = NULL;printf("complex_data_free:free values done\n");}free(data->datas);data->datas = NULL;printf("complex_data_free:done\n");
}int main(int argc, char** argv) {printf("hello world,auto clean up\n");complex_data_t* datas = (complex_data_t*)smalloc(sizeof(complex_data_t), complex_data_free);memset(datas,0,sizeof(complex_data_t));if(datas){datas->datas = malloc(sizeof(char) * 32);datas->values = malloc(sizeof(values_t));if(datas->values){memset(datas->values,0,sizeof(values_t));datas->values->int_values = malloc(sizeof(int32_t));if(datas->values->int_values){memset(datas->values->int_values,0,sizeof(int32_t));}}}sfree(datas);return 0;
}

编译:

gcc -o smalloc smalloc.c

运行结果如下:

hello world,auto clean up
complex_data_free:free int_values done
complex_data_free:free values done
complex_data_free:done

这里的一个缺点是,即使对于简单类型,我们也必须指定一个有效的析构函数,而这对于简单类型来说并不总是可取的,因此允许 NULL 作为一个有效参数,这意味着没有析构函数。

3、小结

在本文中,我们通过使用GCC编译的属性实现了变量和内存管理的简单实现,在实际的智能指针实现中是非常复杂的,例如,unique_ptr,shared_ptr,以及对象引用计数等等这些实现复杂的。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 奇门WMS-A和金蝶云星空单据接口对接
  • linux(debian)迁移home到其他物理盘并扩容——————附带详细步骤
  • 基于hadoop的网络流量分析系统的研究与应用
  • 杂谈c语言——5.类型提升
  • 富格林:揭开黑幕面纱实现安全
  • Spark-环境启动
  • Oracle+ASM+High冗余详解及空间计算
  • Ubuntu24.04使用SRS 搭建 RTMP流媒体服务器
  • `kill -9` 和 `pkill`
  • 31集-33集【求助】AIGC返回的对话内容文字转语音失败-《MCU嵌入式AI开发笔记》
  • 驾驭时间之舟:SQL中时序数据处理的深度探索
  • ActiveMQ、RabbitMQ、Kafka、RocketMQ在事务性消息、性能、高可用和容错、定时消息、负载均衡、刷盘策略的区别
  • MFC系列-改变控件字体和颜色
  • 【经典算法】BFS_FloodFill算法
  • flume系列之:java.lang.OutOfMemoryError: unable to create new native thread
  • CentOS7简单部署NFS
  • Debian下无root权限使用Python访问Oracle
  • iOS高仿微信项目、阴影圆角渐变色效果、卡片动画、波浪动画、路由框架等源码...
  • JavaScript设计模式系列一:工厂模式
  • learning koa2.x
  • niucms就是以城市为分割单位,在上面 小区/乡村/同城论坛+58+团购
  • node入门
  • OpenStack安装流程(juno版)- 添加网络服务(neutron)- controller节点
  • React-flux杂记
  • Service Worker
  • SSH 免密登录
  • Vue.js 移动端适配之 vw 解决方案
  • Vue2.x学习三:事件处理生命周期钩子
  • Web Storage相关
  • 成为一名优秀的Developer的书单
  • 初探 Vue 生命周期和钩子函数
  • 短视频宝贝=慢?阿里巴巴工程师这样秒开短视频
  • 构建工具 - 收藏集 - 掘金
  • 基于Dubbo+ZooKeeper的分布式服务的实现
  • 基于游标的分页接口实现
  • 面试题:给你个id,去拿到name,多叉树遍历
  • 前嗅ForeSpider中数据浏览界面介绍
  • 全栈开发——Linux
  • 小程序01:wepy框架整合iview webapp UI
  • 掌握面试——弹出框的实现(一道题中包含布局/js设计模式)
  • MPAndroidChart 教程:Y轴 YAxis
  • postgresql行列转换函数
  • # 计算机视觉入门
  • #免费 苹果M系芯片Macbook电脑MacOS使用Bash脚本写入(读写)NTFS硬盘教程
  • #知识分享#笔记#学习方法
  • $NOIp2018$劝退记
  • (12)Hive调优——count distinct去重优化
  • (26)4.7 字符函数和字符串函数
  • (9)STL算法之逆转旋转
  • (BAT向)Java岗常问高频面试汇总:MyBatis 微服务 Spring 分布式 MySQL等(1)
  • (LeetCode) T14. Longest Common Prefix
  • (附源码)c#+winform实现远程开机(广域网可用)
  • (附源码)ssm跨平台教学系统 毕业设计 280843
  • (免费领源码)python+django+mysql线上兼职平台系统83320-计算机毕业设计项目选题推荐
  • (十八)用JAVA编写MP3解码器——迷你播放器