C++/CLI: Destructors VS Finalizers
Even though in C# destructor and finalizer are the same thing because C# is garbage collected, in C++/CLI things are quite different. This is because C++/CLI has both deterministic (destructors) and non deterministic destruction (finalizers).
Destructors are deterministically invoked when an object created on the managed stack goes out of scope; on the other hand, finalizers are called by .NET's Garbage Collector when its heuristic says so. That is why it's called non-deterministic destruction.
La sintaxis:
//This generates C4251
public ref class A(){
//Fields
public:
A();
~A(); //Destructor
!A(); //Finalizer
void f();
}
The destructor is automatically called when an instance of A created on the managed stack (without using gcnew/new/New) goes out of scope, and also when the Dispose method is called on an instance created on the managed heap (gcnew/New). This is because the C++/CLI compiler maps the destructor to the Dispose method, which allows us to destroy C++/CLI objects from C#, VB.NET or some other managed language.
However, if we forget to call Dispose for an object created on the heap, GC comes to the rescue. And the finalizer allows us to write code to be ran when the GC cleans it up. How is this related to the destructor? The finalizer calls System::GC::SupressFinalize, which prevents Dispose from being invoked on a finalized object. Other key points:
- A finalizer can only free unmanaged objects/resources, since we cannot tell if an object was finalized before another one.
- As a general rule, only classes with unmanaged resources/objects should implement a finalizer
- Every class which implements a finalzier should also implement a destructor. Have both of them call a ReleaseUnmanagedResources method, so that unmanaged cleanup is defined in only one place
For more details, see chapter 11 of the book "Expert C++/CLI: .NET for Visual C++ Programmers", by Marcus Heege
Comments
Post a Comment