欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 维修 > 【Orange Pi 5嵌入式C语言编程】-智能指针简单实现

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

2024/10/24 14:21:15 来源:https://blog.csdn.net/wujuxKkoolerter/article/details/141275582  浏览:    关键词:【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,以及对象引用计数等等这些实现复杂的。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com