1

I've wrote a C++ library that is exposed to my VB.NET application through a C++/CLI wrapper.

I'm worried about objects that I'm shuttling up to the VB.NET application through the wrapper. To use the classes in the library I've written wrappers for them and the wrapper classes contain pointers to an unmanaged instance of the class. In the destructor of the wrapper class I delete the memory that the unmanaged pointer is pointing to.

If the wrapped .NET library passes one of these class instances to the VB.NET application and the VB.NET application uses it and moves on (doesn't save a reference to it); will the .NET garbage collector come around and dispose this class instance causing the unmanaged memory to be deallocated in the destructor of the class? This would cause an error if I had a reference to this same memory that the wrapped class instance pointed to.

If this is the case then I'll just copy all the data in the wrapper to ensure that my wrappers don't share any data with the native portion of the library. If this isn't the case then do I have to call some sort of dispose method on the wrapped class instance in order to destruct the unmanaged object?

casperOne
  • 73,706
  • 19
  • 184
  • 253
Ian
  • 4,169
  • 3
  • 37
  • 62

2 Answers2

1

In CLI, you simply have to use the destructor syntax (~MyClass()) and the C++/CLI compiler will create an IDisposable implementation on the class for you.

This "destructor" (it's not really, it just has the syntax of one) will be called when the Dispose method is called in unmanaged code. It's here that you would put the calls you need to make in order to release resources.

If you want to implement a finalizer, then you would use the new destructor syntax (!MyClass()). This should release the same resources that you would in your "destructor".

Finally, in your managed code, you simply would reference the IDisposable implementation and then call Dispose on it, more than likely through the using statement.

casperOne
  • 73,706
  • 19
  • 184
  • 253
  • I think I might be getting a little mixed up if I declare both a destructor (~MyClass()) and a finalizer (!MyClass()) and implement them within my c++/cli wrapper, then I will automatically be able to call dispose on these objects, after I cast them to IDisposable. I think I've heard that calling dispose can be dangerous, or maybe that was invoking the garbage collector, I can't remember. – Ian Sep 27 '11 at 21:11
  • @Ian: Calling `Dispose` does *not* call the garbage collector. That's completely false. The destructor (`~`) is for the `IDisposable` implementation whereas the finalizer (`!`) is for the finalizer (which gets called *by* the garbage collector if it is slated for finalization). In general, if you have an unmanaged resource in your CLI class, you should implement `IDisposable` (which `~` makes very easy, obviously) so your managed callers can dispose of the unmanaged resources as soon as possible. – casperOne Sep 27 '11 at 22:14
0

You are mixing it up a bit. Yes, after the vb.net code stops referencing one of your C++/CLI classes then eventually the finalizer will be called after the object got collected. Note that this is the finalizer, it has nothing to do with dispose. Your C++/CLI object should provide both a destructor (called by Dispose()) and a finalizer.

There is otherwise no danger of memory corruption. The finalizer only gets called when the garbage collector cannot find any live references to the object. Since there is no reference left, there's no way that you can accidentally access the deleted native object. Check this answer for the standard pattern.

Community
  • 1
  • 1
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Well if I have a native pointer in the library that still references that memory then the garbage collector might (indirectly) dispose of it and my unmanaged reference in the library would cause an error right? I'm guessing the garbage collector doesn't check the unmanaged pointers within a c++/cli class to see if those point to memory that is pointed to somewhere else. – Ian Sep 27 '11 at 21:05
  • No, that's up to you. Use, say, shared_ptr<>. All that you know is that the managed code will never use it again. Do consider if it still makes sense to keep that object alive if the managed code has no way left to do anything with it. I can't tell whether that's relevant. – Hans Passant Sep 27 '11 at 21:10
  • Okay, thanks. In my case it does make sense, because the library has a list of objects that persist, but on occasion those objects are passed to the .NET application. I'll just have to make sure I do a data copy and delete the memory that I copy to. – Ian Sep 27 '11 at 21:17
  • "Since there is no reference left, there's no way that you can accidentally access the deleted native object" FALSE. Other objects in the finalizer queue might still attempt to use it. – Ben Voigt Sep 27 '11 at 23:53
  • Mr downvoting wet blanket showed up again. Interesting conversation about the plumbing, let's see where it goes to get the insights. Kadunk, over. – Hans Passant Sep 28 '11 at 00:13