Bern McCarty wrote:
>
Does the below program use ~T and !T
correctly to deal with the managed and native resources of MyClass?
I think it's all correct.
If a
type has native resources then you have to make sure to free them from
both !T and ~T.
Yes, you did that right. Although I'm usually not very happy about
placing "naked" native pointers in any class, whether it's managed or
native. In a native application, I'd use boost::shared_ptr or
boost::scoped_ptr to guard that native object. I've worked out a similar
template for managed classes:
http://tweakbits.com/CliScopedPtr.h
Using this template you can ensure that the owned native objects are
deleted automatically, no matter what (if Dispose is not called, then
the finalizer will take care of it). Here's how to use it:
#include "CliScopedPtr.h"
ref class MyClass
{
public:
MyClass()
: native1(new MyNativeType),
native2(new MyNativeType2)
{ }
private:
CliScopedPtr<MyNativeTypenative1;
CliScopedPtr<MyNativeType2native2;
};
You don't even need to declare any destructor or finalizer (except for
your Assert, but not for resource management). The compiler will
automatically implement those, and will inherit from IDisposable too.
You'll never miss another delete. Of course MyClass is a resource now
(thanks to the CliScopedPtr members), so it is strongly recommended to
call Dispose on it (the compiler implicitly generates the Dispose() for
MyClass; in C++/CLI you call delete, in other languages you call Dispose()).
Note that CliScopedPtr holds a native pointer, never a managed object.
I'm not trying to force this on you at all; what you're doing is
perfectly fine. When I program in native C++, I certainly use smart
pointers. I may be overreacting here, but I prefer doing the same for
native resources inside managed classes. I'm aware that this adds a
little bit of an overhead to the code, therefore it is not always advisable.
Exception safety inside a constructor is not that important in managed
code, because when any exception is thrown from the constructor, the
destructor is still being called (unlike in ISO C++). So the importance
of CliScopedPtr is certainly much smaller than the importance of smart
pointers in native C++.
Is there a convention for the naming of this
routine that has been agreed to to any extent? DisposeNativeResources()?
That sounds good to me. I'm not aware of any naming the standard
recommends. The convention that others are using is this:
~T() { this->!T(); }
Which you can rule out if you want to place an Assert in your finalizer.
What you're doing is not a bad idea, but it will only work with your own
classes. There are commercial memory leak detectors that can point out
these problems, and even more. Nevertheless, the Assert may still be a
good idea in many cases, and it comes free.
ref class MyClass : System::IDisposable
{
It is not required that you inherit from IDisposable. If your ref class
declares a destructor, the compiler automatically makes the class an
IDisposable.
Tom