用纯 C 实现 RAII?
是否可以在纯 C 中实现 RAII ?
我认为以任何理智的方式都是不可能的,但也许使用某种肮脏的技巧是可能的。 我想到的是重载标准的 free 函数,或者可能覆盖堆栈上的返回地址,以便当函数返回时,它会调用其他以某种方式释放资源的函数? 或者也许有一些 setjmp/longjmp 技巧?
这纯粹是出于学术兴趣,我无意实际编写如此不可移植且疯狂的代码,但我想知道这是否可能。
Is it possible to implement RAII in pure C?
I assume it isn't possible in any sane way, but perhaps is it possible using some kind of dirty trick. Overloading the standard free
function comes to mind or perhaps overwriting the return address on the stack so that when the function returns, it calls some other function that somehow releases resources? Or maybe with some setjmp/longjmp trick?
This is of a purely academic interest and I have no intention of actually writing such unportable and crazy code but I'm wondering if that is at all possible.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
这是固有的依赖于实现的,因为标准不包括这种可能性。 对于 GCC,
cleanup
属性在变量超出范围时运行函数:打印:
请参阅 此处
This is inherent implementation dependent, since the Standard doesn't include such a possibility. For GCC, the
cleanup
attribute runs a function when a variable goes out of scope:Prints:
See here
将 RAII 引入 C 的一种解决方案(当您没有
cleanup()
时)是用执行清理的代码包装函数调用。 这也可以打包在一个整洁的宏中(如最后所示)。您可以使用宏表达
SomeFunction
中的所有样板代码,因为每次调用都是相同的。例如:
注意:您希望使用高级宏框架(例如 P99)来使上述内容成为可能。
One solution to bring RAII to C (when you don't have
cleanup()
) is to wrap your function call with code that will perform a cleanup. This can also be packaged in a tidy macro (shown at the end).You can express all of the boiler plate code in
SomeFunction
with macros since it will be the same for every call.For example:
Note: you'd want to make use of an advanced macro framework such as P99 to make something like the above possible.
如果您的编译器支持 C99(甚至是其中的很大一部分),您可以使用可变长度数组 (VLA),例如:
如果没记错的话,gcc 在添加到 C99 之前就已经/支持此功能了。 这(大致)相当于以下简单情况:
但是,它不允许您执行 dtor 可以执行的任何其他操作,例如关闭文件、数据库连接等。
If your compiler supports C99 (or even a substantial part of it) you can use a variable length array (VLA), such as:
If memory serves, gcc had/supported this feature well before it was added to C99. This is (roughly) equivalent to the simple case of:
It does not, however, let you do any of the other things a dtor can do such as closing files, database connections, etc.
可能最简单的方法是使用 goto 跳转到函数末尾的标签,但这对于您正在查看的类型来说可能过于手动。
Probably the easiest way is to use goto to jump to a label at the end of a function but that's probably too manual for the sort of thing you're looking at.
我会选择覆盖堆栈上的返回地址。 它会成为最透明的。 替换
free
仅适用于堆分配的“对象”。I'd opt for overwriting the return address on the stack. It'd work out as the most transparent. Replacing
free
will only work with heap-allocated "objects".你看过 alloca() 吗? 当 var 离开作用域时它将释放。 但为了有效地使用它,调用者必须始终在将其发送到事物之前执行分配...如果您正在实现 strdup,那么,您不能使用分配。
Have you looked at alloca()? It will free when an var leaves scope. But to use it effecticly the caller must always do the alloca before sending it to things... If you were implementing strdup, well, you can't use alloca.
为了补充约翰内斯答案的这一部分:
cleanup 属性有一个限制 (http://gcc.gnu.org/onlinedocs/gcc-4.0.4/gcc/Variable-Attributes.html):此属性只能应用于 auto 函数作用域变量。
因此,如果文件中有静态变量,则可以通过以下方式为静态变量实现 RAII:
这是一个测试:
To complement this part of Johannes's answer:
There is a limitation on cleanup attribute (http://gcc.gnu.org/onlinedocs/gcc-4.0.4/gcc/Variable-Attributes.html): This attribute can only be applied to auto function scope variables.
So if there is a static variable in a file it is possible to implement RAII for a static variable in this way:
This is a test:
检查 https://github.com/psevon/exceptions-and-raii-in- c 用于唯一和共享智能指针和异常的 C 实现。 此实现依赖于宏括号 BEGIN ... END 替换大括号并检测超出范围的智能指针,以及返回的宏替换。
Check https://github.com/psevon/exceptions-and-raii-in-c for a C implementation of unique and shared smartpointers and exceptions. This implementation relies on macro brackets BEGIN ... END replacing braces and detecting smartpointers going out of scope, as well as macro replacement for return.
我之前不知道属性清理。 当然,这是一个适用的简洁解决方案,但它似乎在基于 setjmp/longjmp 的异常实现中表现不佳; 抛出异常的作用域和捕获异常的作用域之间的任何中间作用域/函数都不会调用清理函数。 Alloca 没有这个问题,但使用 alloca 时,您无法将内存块的所有权从调用它的函数转移到外部作用域,因为内存是从堆栈帧分配的。 可以实现有点类似于 C++ unique_ptr 和共享_ptr 的智能指针,认为它需要使用宏括号而不是 {} 并返回,以便能够将额外的逻辑与作用域进入/退出关联起来。 请参阅 https://github.com/psevon/exceptions-and- 中的 autocleanup.c raii-in-c 的实现。
I didn't know about attribute cleanup before. Certainly a neat solution where it's applicable, but it doesn't seem to behave well with setjmp/longjmp based exception implementations; the cleanup function is not called for any intermediate scopes/functions between the scope that threw the exception and the scope that catches it. Alloca doesn't have this problem, but with alloca you cannot transfer ownership of the memory chunk to an outer scope from the function that called it since the memory is allocated from the stack frame. It's possible to implement smartpointers somewhat akin to C++ unique_ptr and shared_ptr, thought it requires using macro brackets instead of {} and return to be able to associate extra logic to scope entry/exit. See autocleanup.c in https://github.com/psevon/exceptions-and-raii-in-c for an implementation.
/*
示例代码
*/
/*
sample code
*/