Вопрос: Почему Java / C # не может реализовать RAII?
Пояснение: я знаю, что сборщик мусора не является детерминированным. Таким образом, при использовании текущих возможностей языка метод Dispose () объекта не может быть вызван автоматически при выходе из области видимости. Но можно ли добавить такую детерминистическую функцию?
Мое понимание:
Я считаю, что реализация RAII должна удовлетворять двум требованиям:
1. Время жизни ресурса должно быть связано с областью действия.
2. Неявный. Освобождение ресурса должно происходить без явного заявления программиста. Аналог сборщика мусора, освобождающего память без явного заявления. «Неявность» должна происходить только в момент использования класса. Создатель библиотеки классов, конечно, должен явно реализовать деструктор или метод Dispose ().
Java / C # удовлетворяет пункт 1. В C # ресурс, реализующий IDisposable, может быть связан с областью использования:
void test()
{
using(Resource r = new Resource())
{
r.foo();
}//resource released on scope exit
}
Это не удовлетворяет пункт 2. Программист должен явно привязать объект к специальной области «использования». Программисты могут (и делают) забыть явно привязать ресурс к области видимости, создав утечку.
Фактически блоки "using" преобразуются компилятором в код try-finally-dispose (). Он имеет такую же явную природу шаблона try-finally-dispose (). Без неявного освобождения крючок для области видимости является синтаксическим сахаром.
void test()
{
//Programmer forgot (or was not aware of the need) to explicitly
//bind Resource to a scope.
Resource r = new Resource();
r.foo();
}//resource leaked!!!
Я думаю, что стоит создать языковую функцию в Java / C #, позволяющую специальным объектам подключаться к стеку через смарт-указатель. Эта функция позволит вам пометить класс как ограниченный областью действия, чтобы он всегда создавался с привязкой к стеку. Могут быть варианты для различных типов умных указателей.
class Resource - ScopeBound
{
/* class details */
void Dispose()
{
//free resource
}
}
void test()
{
//class Resource was flagged as ScopeBound so the tie to the stack is implicit.
Resource r = new Resource(); //r is a smart-pointer
r.foo();
}//resource released on scope exit.
Я думаю, что неявность "стоит того". Так же, как неявность сборки мусора "стоит того". Явное использование блоков освежает глаза, но не дает семантического преимущества перед try-finally-dispose ().
Нецелесообразно ли реализовывать такую функцию в языках Java / C #? Может ли он быть введен без нарушения старого кода?
using
выполнения Dispose
будет гарантировано (хорошо, дисконтирование процесса внезапно умирают без выброса исключения, в этот момент всех очистки предположительно становятся спорным).
struct
), но они , как правило , избегать , за исключением особых случаев. Смотрите также .
Dispose
s будут всегда работать, независимо от того, как они вызвали. Добавление неявного уничтожения в конце области не поможет этому.