c语言自动内存回收(RAII实现)

RAII(ResourceAcquisitionIsInitialization)是一种编程策略,用于在C++中管理资源。本文介绍了如何在C语言中使用编译属性__attribute__(cleanup)实现类似RAII的功能,通过示例展示了如何自动释放内存、关闭文件和解锁,以提高代码的安全性和可维护性。虽然此特性不被所有编译器支持,但可以提供一种避免资源泄露的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简述

什么是RAII

RAII(Resource Acquisition Is Initialization)是c++之父Bjarne Stroustrup提出的概念。资源一般分三个步骤:获取、使用和销毁,而在自由使用内存的c语言中,资源的销毁常常是程序员容易遗漏的事情,让程序自动销毁资源也成为了业界的常规方案。

c实现

/* 入参是析构函数,在malloc资源时也指定free要使用的函数,尽量不在宏中写函数,减少后续定位的复杂度,并且也满足malloc和free的配对出现,可读性更好 */
#define RAII_FREE(FreeFunc) __attribute__((cleanup(FreeFunc)))

以上代码使用了编译属性__attribute__,在函数退出后自动回收资源,使用方式如下:

  • 示例一:释放内存
void MemFreeL2PointerAndSetNull(void *ptr)
{
    void **pptr = (void **) ptr;
    if (*pptr != NULL)
    {
        free(*pptr);
        *pptr = NULL;
    }
}

void TestFunc()
{
    RAII_FREE(MemFreeL2PointerAndSetNull) TestObj *obj = (TestObj *)malloc(sizeof(TestObj));
    obj->grade = 1;
}
  • 示例二:关闭文件
void CloseFile(void *ptr)
{
    void **pptr = (void **) ptr;
    if (*pptr != NULL)
    {
        (void) fclose(*pptr);
    }
}

void test_whenOpenFile_thenCloseFile(const char *flePath)
{
    RAII_FREE(CloseFile) FILE *handle = fopen(flePath, "r");
    if (!handle)
    {
        printf("open file filed");
    }
}
  • 示例三:释放锁
void ReleaseMutexLock(void *ptr)
{
    void **pptr = (void **) ptr;
    if (*pptr != NULL)
    {
        pthread_mutex_unlock(*pptr);
    }
}

void test_whenLock_thenFree(pthread_mutex_t *lock)
{
    RAII_FREE(ReleaseMutexLock) pthread_mutex_t *mutex = lock;
    pthread_mutex_lock(mutex);
}

理论依据

1、现有的语言c++、rust都有RAII的实现
2、 Linux平台下最常用的C语言函数库 (glib) 中的公共 API (g_autoptr)中使用了该能力
3、A simple defer feature for C(2021)这篇论文也讨论了c的defer关键字,即在函数返回之前执行,原理跟cleanup是一样的

考虑到__attribute__是编译属性,笔者调研了几款常见编译器,支持程度如下:

编译器是否支持参考
GCC支持https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html
Clang支持https://clang.llvm.org/docs/AttributeReference.html
MSVC不支持,可以通过 _try 和 _finally 关键字实现类似的功能https://learn.microsoft.com/en-us/cpp/c-language/try-finally-statement-c?view=msvc-170

优缺点

  • 优点:
    • 宏简单易用,并且没有在宏里定义复杂逻辑,debug和运维都很方便
    • 使代码结构简单画(减少变量/资源清理的代码或者goto跳转)
    • 降低内存泄露、打开文件、锁定互斥锁的风险
  • 缺点:
    • 不完全惯用的c风格
    • 需要依赖编译器来清理

扩展

  • 智能指针:FreeFunc中加入引用技术,则可实现c++中的智能指针功能

参考

RAII in C: cleanup gcc compiler extension

A simple defer feature for C

Add support for GCC-like cleanup attribute for plain C

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值