与传统的 C++ 相比,许多语言使编写自定义内部块处理器†</sup> 变得容易得多(这可能已在最新标准的当前草案中得到解决)。有了这些,使用 RAII 进行精确资源处理的要求就变得不那么紧迫了;你可以这样做:
using (Transaction t = makeTX()) {
// blah
}
代替:
{
Transaction t = makeTX();
// blah
}
除了当您有多个嵌套using
构造时,资源释放的顺序更清楚之外,实际上并没有太大的区别。(在引发异常的情况下,IMO 也更容易进行特殊处理,这对于您想要回滚错误的事务之类的事情很有用,但我不希望每个人都同意我的观点。)另请注意有许多不同的编写using
结构的方式,其中一些比其他的更重量级,但我们真的不需要在这里探索不同之处。
鉴于以这种不同的方式处理精确的资源处理,对 C++ RAII 样式的需求要少得多,并且使用垃圾收集 (GC) 代替是可行的,因为它可以处理复杂的情况(即,任何难以处理的地方)将对象生命周期绑定到特定范围)更容易。公平地说,在某些情况下,您需要在不平凡的生命周期内进行精确的资源管理,但这些情况对每个人来说都是令人讨厌的。
Perl 使用垃圾收集并具有廉价的子例程块,就像大多数其他脚本语言以一种或另一种形式一样(因为在脚本语言中代码和数据之间的划分比更传统的编译语言更松散)。我知道的唯一不使用 GC 的大型脚本语言是 Tcl,这是因为由于技术语义原因,那里的值系统保证无循环,因此引用计数就足够了。不过那里的代码块仍然很便宜。
如果我们看一下主流编译语言(即,不是脚本语言),那么我们确实在 1990 年左右看到了分歧。在那之前的语言(包括 C++)往往不假设垃圾收集(除了一些例外,例如 Lisp、Smalltalk 和函数式编程语言),而此后的语言(尤其是 Java 和 C#)确实假设 GC。我想关于这一点有一个重大的哲学转变,可能与一些聪明的实现相结合,这些实现在此之前处理了 GC 中最令人震惊的问题。当您拥有 GC 时,您根本不会认为 RAII 是一种解决方案。它非常植根于 C++ 的世界模型。
†</sup> 我只是编造了这个词。