crear c# garbage-collection c++-cli finalizer

c# - crear - C++/CLI: prevención de la recolección de elementos no utilizados en contenedor administrado de recursos no administrados



destructor c# (2)

Tengo un NativeDog clase C ++ no NativeDog que debe usarse desde C #, así que he creado una clase de contenedor ManagedDog .

// unmanaged C++ class class NativeDog { NativeDog(...); // constructor ~NativeDog(); // destructor ... } // C++/CLI wrapper class ref class ManagedDog { NativeDog* innerObject; // unmanaged, but private, won''t be seen from C# ManagedDog(...) { innerObject = new NativeDog(...); ... } ~ManagedDog() // destructor (like Dispose() in C#) { // free unmanaged resources if (innerObject) delete innerObject; } !ManagedDog() // finalizer (like Finalize() in C#, in case { // the user forgets to dispose) ~ManagedDog(); // call destructor } }

Todo está bien, y uso la clase de esta manera:

// in C++/CLI // this function is called from C++ code void MyLibrary::FeedDogNative(NativeDog* nativedog) { ... // (***) } // this function is called from C#, passes on the dog to the native function void MyLibrary::FeedDogManaged(ManagedDog^ dog) { NativeDog* rawdog = dog->innerObject; MyLibrary::FeedDogNative(rawdog); } // C# client code void MyFunc() { ManagedDog dog = new ManagedDog(...); MyLibrary.FeedDogManaged(dog); }

¿Ves lo que está mal? Yo tampoco lo hice al principio, hasta que cosas muy extrañas comenzaron a suceder de vez en cuando. Básicamente, si después de llamar a MyFunc() el programa está pausado por el GC mientras se encuentra en alguna parte de la función nativa FeedDogNative (marcada (***) arriba), pensará que el contenedor gestionado se puede recopilar porque ya no se usará. ni en C # MyFunc (es una variable local y no se usará después de la llamada FeedDogManaged ), ni en FeedDogManaged . Y esto en realidad sucedió en ocasiones. El GC llama al Finalizador, que delete el objeto del perro nativo, ¡aunque FeedDogNative no ha terminado de usarlo! Entonces mi código no administrado ahora está usando un puntero eliminado.

¿Cómo puedo prevenir esto? Puedo pensar en algunas formas (por ejemplo, una llamada falsa que pretende usar el dog al final de FeedDogManaged ), pero ¿cuál sería la forma recomendada?



Necesita una llamada GC::KeepAlive() en su función FeedDogManaged . Parece que es un caso de uso exacto para eso.