Многие языки значительно облегчают написание собственного процессора внутренних блоков † , чем это было традиционно в C ++ (это, возможно, было решено в текущих проектах последнего стандарта). Когда они у вас есть, большая часть требований использования RAII для точной обработки ресурсов становится гораздо менее актуальной; Вы можете сделать что-то вроде этого:
using (Transaction t = makeTX()) {
// blah
}
вместо:
{
Transaction t = makeTX();
// blah
}
На самом деле нет большой разницы, за исключением того, что, когда у вас есть несколько вложенных using
конструкций, гораздо яснее, каков порядок выпуска ресурсов. (Также IMO проще сделать специальную обработку в случае, когда выдается исключение, полезно для таких вещей, как транзакции, когда вы хотите откатиться при ошибке, но я не ожидаю, что все согласятся со мной.) Также обратите внимание что существует множество различных способов написания using
конструкций, некоторые из которых гораздо более тяжелые, чем другие, но нам не нужно изучать различия здесь.
Учитывая, что точная обработка ресурсов рассматривается по-другому, спрос на стиль CII RAII намного меньше, и вместо него целесообразно использовать сборщик мусора (GC), поскольку он обрабатывает сложные случаи (т. Е. Везде, где трудно привязать время жизни объекта к определенной области) гораздо проще. Чтобы быть справедливым, есть случаи, когда вам нужно точное управление ресурсами с нетривиальным временем жизни, но эти случаи неприятны для всех .
Perl использует сборщик мусора и имеет дешевые блоки подпрограмм, как и большинство других языков сценариев в той или иной форме (поскольку разделение между кодом и данными в языках сценариев более свободно, чем в более традиционных компилируемых языках). Единственный большой язык сценариев, который мне известен, который не использует GC, - это Tcl, и это потому, что система ценностей там гарантированно не имеет циклов по техническим семантическим причинам, и поэтому достаточно подсчета ссылок. Блоки кода все еще очень дешевые там.
Если мы посмотрим на основные скомпилированные языки (т. Е. Не языки сценариев), то мы действительно увидим разрыв примерно в 1990 году. Языки до этого времени (включая C ++), как правило, не предполагают сборку мусора (с некоторыми исключениями, такими как Lisp, Smalltalk) и функциональные языки программирования), тогда как языки после этого момента (особенно Java и C #) do предполагают GC. Я полагаю, что по этому вопросу произошел существенный философский сдвиг, возможно, в сочетании с некоторыми умными реализациями, которые до этого момента имели дело с наиболее вопиющими проблемами в GC. Когда у вас есть GC, вы просто не думаете о RAII как о решении; это очень укоренено в модели мира C ++.
† Я только что увеличил этот термин.