Pergunta: Por que o Java / C # não pode implementar o RAII?
Esclarecimento: Estou ciente de que o coletor de lixo não é determinístico. Portanto, com os recursos de idioma atuais, não é possível que o método Dispose () de um objeto seja chamado automaticamente na saída do escopo. Mas um recurso tão determinístico poderia ser adicionado?
Meu entendimento:
Eu sinto que uma implementação do RAII deve atender a dois requisitos:
1. A vida útil de um recurso deve estar vinculada a um escopo.
2. Implícito. A liberação do recurso deve ocorrer sem uma declaração explícita do programador. Análogo a um coletor de lixo, liberando memória sem uma declaração explícita. A "implicitude" só precisa ocorrer no ponto de uso da classe. É claro que o criador da biblioteca de classes deve implementar explicitamente um destruidor ou um método Dispose ().
Java / C # satisfaz o ponto 1. No C #, um recurso implementando IDisposable pode ser vinculado a um escopo "using":
void test()
{
using(Resource r = new Resource())
{
r.foo();
}//resource released on scope exit
}
Isso não atende ao ponto 2. O programador deve vincular explicitamente o objeto a um escopo especial "usando". Os programadores podem (e fazem) esquecer de vincular explicitamente o recurso a um escopo, criando um vazamento.
De fato, os blocos "using" são convertidos para o código try-finally-dispose () pelo compilador. Ele tem a mesma natureza explícita do padrão try-finalmente-dispose (). Sem uma liberação implícita, o gancho para um escopo é o açúcar sintático.
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!!!
Eu acho que vale a pena criar um recurso de linguagem em Java / C # que permita objetos especiais conectados à pilha por meio de um ponteiro inteligente. O recurso permitiria sinalizar uma classe como vinculada ao escopo, para que ela sempre seja criada com um gancho na pilha. Pode haver opções para diferentes tipos de ponteiros inteligentes.
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.
Eu acho que implícita "vale a pena". Assim como a implicitude da coleta de lixo "vale a pena". Blocos usando explícitos são refrescantes para os olhos, mas não oferecem vantagem semântica sobre o try-finalmente-dispose ().
É impraticável implementar esse recurso nas linguagens Java / C #? Poderia ser introduzido sem quebrar o código antigo?
using
a execução de Dispose
é garantida (bem, descontar o processo de repente morrer sem que uma exceção seja lançada; nesse ponto, toda a limpeza presumivelmente se torna discutível).
struct
), mas eles são tipicamente evitado exceto em casos muito especiais. Veja também .
Dispose
s são sempre executado, independentemente de como eles são acionados. Adicionar destruição implícita no final do escopo não ajudará nisso.