C++/CLI: Destructores VS Finalizers
Aunque en C# estas dos palabras representan lo mismo, dado que C# es un lenguaje con recolección de basura, en C++/CLI la cosa es muy diferente. Esto se debe a que dicho lenguaje tiene tanto destrucción determinística (destructores) como no determinística (finalizers).
Los destructores son invocados determinísticamente al irse de scope el objeto; por otro lado, los finalizers son invocados por el recolector de basura de .NET cuando su heurística lo indique. Es por ello que dicha destrucción se denomina "no deterministica."
La sintaxis:
//Esto genera C4251
public ref class A(){
//Atributos
public:
A();
~A(); //Destructor
!A(); //Finalizer
void f();
}
El destructor es invocado cuando una instancia de A creada en el managed stack (o sea, sin usar gcnew/New/new) se va de scope, y cuando se invoca Dispose sobre una instancia creada en managed heap. Esto último es porque el compilador de C++/CLI mapea el destructor a Dispose, lo cual nos permite destruir objetos C++/CLI desde VB.NET, C# u otro lenguaje de .NET.
Sin embargo, si nos olvidamos de invocar a Dispose para un objeto creado en el heap, el GC acude a nuestro rescate. Y el finalizer nos permite poner código que se ejecute cuando el GC destruye el objeto. ¿Cómo se relaciona con el destructor? El finalizer llama a System::GC::SuppressFinalize, lo cual evita que se invoque Dispose sobre un objeto finalizado. Puntos clave:
- Un finalizer sólo puede liberar recursos nativos, porque al ser el GC no determinístico, no se puede saber si un objeto fue finalizado antes que otro
- Salvo casos excepcionales, sólo las clases con recursos nativos/no manejados deben implementar un finalizer
- Toda clase que implemente un finalizer debería implementar un destructor para destrucción determinística
Para más detalles, ver el Capítulo 11 del libro "Expert C++/CLI: .NET for Visual C++ Programmers", de Marcus Heege
Comments
Post a Comment