RAII = 资源获取即初始化
参考计数=“穷人的GC”
它们一起非常强大(就像一个引用计数的 3D 对象持有一个 VBO,当它的析构函数被调用时它会抛出释放)。
现在,问题是——除了 C++ 之外,RAII 是否存在于任何语言中?特别是,不允许指针算术/缓冲区溢出的语言?
RAII = 资源获取即初始化
参考计数=“穷人的GC”
它们一起非常强大(就像一个引用计数的 3D 对象持有一个 VBO,当它的析构函数被调用时它会抛出释放)。
现在,问题是——除了 C++ 之外,RAII 是否存在于任何语言中?特别是,不允许指针算术/缓冲区溢出的语言?
D 有 RAII 但仍然有指针算术 :( 但是,你真的不必使用它。请注意让 D 工作对我来说是一件痛苦的事,所以我只是说。
Perl 5 具有引用计数和析构函数,当所有引用超出范围时保证会调用它们,因此 RAII 在该语言中可用,尽管大多数 Perl 程序员不使用该术语。
并且 Perl 5 不公开指向 Perl 代码的原始指针。
然而,Perl 6 有一个真正的垃圾收集器,实际上允许关闭垃圾收集器;所以你不能依赖以任何特定顺序收集的东西。
我相信 Python 和 Lua 使用引用计数。
perl、python (C)、php 和 tcl 是引用计数的,并且一旦对象的引用计数变为零就会销毁对象,一旦变量超出范围,就会发生这种情况。内置类型会自动释放。用户定义的类有一种方法来定义将在发布时调用的析构函数。
有一些边缘情况:全局变量可能要到最后才释放,循环引用可能要到最后才释放(尽管 php 最近实现了一个 gc 来处理这种情况,python 2 添加了一个循环检测器)。
Python(标准 CPython,而不是 Jython、Unladen Swallow 和 IronPython 等变体)对其对象使用引用计数。
有了它,它还具有 RAII 和(大部分)确定性垃圾收集。例如,这应该可以确定性地关闭文件:
def a():
fp = open('/my/file', 'r')
return fp.read()
注意fp.close()
永远不会被调用。一旦fp
超出范围,对象就应该被销毁。但是,在某些情况下不能保证确定性最终确定,例如:
sys.last_traceback
保留最后的回溯)因此,虽然 python 理论上具有确定性终结,但最好显式关闭任何可能异常(如 IOError 等)可能导致对象保持活动的资源。
Vala的对象内存管理基于引用计数,并且它具有 RAII(在某种意义上,它的析构函数被确定性地调用)。典型的用例是创建 GUI,其中引用计数的开销通常可以忽略不计。您可以使用指针并绕过引用计数,例如为了互操作性,或者如果您需要额外的性能,但在大多数情况下,您可以在没有指针的情况下生活。它还做了一些聪明的事情,您可以将引用标记为owned
orunowned
并转移所有权,并且在许多情况下,它能够省略引用计数(例如,如果对象没有转义函数)。Vala 与 GObject/GTK 密切相关,因此只有在您想在该生态系统中工作时才有意义。
另一个有趣的候选者是Rust。虽然它也有指针和垃圾收集,但两者都是可选的。您可以完全使用与 C++ 的智能指针等效的程序编写程序,保证没有泄漏,并且它支持 RAII。它也有一个引用所有权的概念,就像 Vala,但有点复杂。从本质上讲,Rust 让您可以完全控制管理内存的方式。您可以在裸机级别工作,甚至可以在其中编写内核,或者您可以在高级别的 GC 上工作,或者介于两者之间的任何东西,并且大多数情况下它可以保护您免受内存或其他指针泄漏 -相关的错误。缺点是它非常复杂,而且由于它仍在开发中,事情可能会发生变化。