Есть много причин, почему RAII не известен лучше. Во-первых, имя не особенно очевидно. Если бы я еще не знал, что такое RAII, я бы точно не догадался об этом по названию. (Получение ресурсов - это инициализация? Какое это имеет отношение к деструктору или очистке, что действительно характеризует RAII?)
Другое - это то, что он не работает так же хорошо в языках без детерминированной очистки.
В C ++ мы точно знаем, когда вызывается деструктор, мы знаем порядок, в котором вызываются деструкторы, и мы можем определить их, чтобы они делали что угодно.
В большинстве современных языков все собирается мусором, что делает реализацию RAII более сложной. Нет причины, по которой было бы невозможно добавить RAII-расширения, скажем, в C #, но это не так очевидно, как в C ++. Но, как уже упоминали другие, Perl и другие языки поддерживают RAII, несмотря на сборку мусора.
Тем не менее, все еще возможно создать свою собственную оболочку в стиле RAII на C # или других языках. Я сделал это в C # некоторое время назад.
Мне нужно было что-то написать, чтобы соединение с базой данных было закрыто сразу после использования - задача, которую любой программист на С ++ считает очевидным кандидатом на RAII.
Конечно, мы можем обернуть все в using
-состояниях всякий раз, когда мы используем соединение с БД, но это просто грязно и подвержено ошибкам.
Мое решение состояло в том, чтобы написать вспомогательную функцию, которая принимала делегат в качестве аргумента, а затем при вызове открывала соединение с базой данных и внутри оператора using передавала его функции делегата, псевдокод:
T RAIIWrapper<T>(Func<DbConnection, T> f){
using (var db = new DbConnection()){
return f(db);
}
}
Все еще не так хорошо или очевидно, как C ++ - RAII, но он достиг примерно того же самого. Всякий раз, когда нам нужен DbConnection, мы должны вызывать эту вспомогательную функцию, которая гарантирует, что она будет закрыта впоследствии.