当前位置:  开发笔记 > 编程语言 > 正文

在纯C中实现RAII?

如何解决《在纯C中实现RAII?》经验,为你挑选了3个好方法。

是否有可能在纯C中实现RAII?

我认为不可能以任何理智的方式,但也许可能使用某种肮脏的技巧.重载标准free函数会想到或者可能覆盖堆栈上的返回地址,这样当函数返回时,它会调用一些其他函数以某种方式释放资源?或者也许有一些setjmp/longjmp技巧?

这纯粹是学术上的兴趣,我无意写出这种不可移植和疯狂的代码,但我想知道这是否可能.



1> Johannes Sch..:

这是固有的实现依赖,因为标准不包括这种可能性.对于GCC,cleanup当变量超出范围时,该属性会运行一个函数:

#include 

void scoped(int * pvariable) {
    printf("variable (%d) goes out of scope\n", *pvariable);
}

int main(void) {
    printf("before scope\n");
    {
        int watched __attribute__((cleanup (scoped)));
        watched = 42;
    }
    printf("after scope\n");
}

打印:

before scope
variable (42) goes out of scope
after scope

看到这里


这比我想象的还要整齐!

2> Keldon Alley..:

将RAII引入C(当你没有cleanup())的一个解决方案是使用将执行清理的代码包装你的函数调用.这也可以打包在一个整洁的宏(最后显示).

/* Publicly known method */
void SomeFunction() {
  /* Create raii object, which holds records of object pointers and a
     destruction method for that object (or null if not needed). */
  Raii raii;
  RaiiCreate(&raii);

  /* Call function implementation */
  SomeFunctionImpl(&raii);

  /* This method calls the destruction code for each object. */
  RaiiDestroyAll(&raii);
}

/* Hidden method that carries out implementation. */
void SomeFunctionImpl(Raii *raii) {
  MyStruct *object;
  MyStruct *eventually_destroyed_object;
  int *pretend_value;

  /* Create a MyStruct object, passing the destruction method for
     MyStruct objects. */
  object = RaiiAdd(raii, MyStructCreate(), MyStructDestroy);

  /* Create a MyStruct object (adding it to raii), which will later
     be removed before returning. */
  eventually_destroyed_object = RaiiAdd(raii,
      MyStructCreate(), MyStructDestroy);

  /* Create an int, passing a null destruction method. */
  pretend_value = RaiiAdd(raii, malloc(sizeof(int)), 0);

  /* ... implementation ... */

  /* Destroy object (calling destruction method). */
  RaiiDestroy(raii, eventually_destroyed_object);

  /* or ... */
  RaiiForgetAbout(raii, eventually_destroyed_object);
}

您可以SomeFunction使用宏来表示所有锅炉板代码,因为每次调用都是相同的.

例如:

/* Declares Matrix * MatrixMultiply(Matrix * first, Matrix * second, Network * network) */
RTN_RAII(Matrix *, MatrixMultiply, Matrix *, first, Matrix *, second, Network *, network, {
  Processor *processor = RaiiAdd(raii, ProcessorCreate(), ProcessorDestroy);
  Matrix *result = MatrixCreate();
  processor->multiply(result, first, second);
  return processor;
});

void SomeOtherCode(...) {
  /* ... */
  Matrix * result = MatrixMultiply(first, second, network);
  /* ... */
}

注意:你想要使用像P99这样的高级宏框架来制作类似上面的东西.


显然,C无法执行基于自动作用域的清理。从这个问题开始:“我认为这不可能以任何理智的方式出现,但也许有可能使用某种肮脏的把戏”。我提供的是一种解决方法,您可以借助简单的宏在C中进行*托管*清理,而无需手动调用destroy或清理(清理将在宏中完成),但是您将需要注册指针。

3> Jerry Coffin..:

如果您的编译器支持C99(或者甚至是其中很大一部分),您可以使用可变长度数组(VLA),例如:

int f(int x) { 
    int vla[x];

    // ...
}

如果内存服务,gcc在添加到C99之前已经/支持了这个功能.这(大致)相当于以下简单情况:

int f(int x) { 
    int *vla=malloc(sizeof(int) *x);
    /* ... */
    free vla;
}

但是,它不允许您执行dtor可以执行的任何其他操作,例如关闭文件,数据库连接等.

推荐阅读
黄晓敏3023
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有