Link to home
Start Free TrialLog in
Avatar of jxbma
jxbmaFlag for United States of America

asked on

Why does the destructor for my CLI/CPP ref class not get called (which results in a memory leak)?

Hi:

I have some questions regarding use of gcnew and explicitly calling delete on the created object.
It appears that I have a leak in my code.

Consider the following example.

I have an unmanaged class:
public class FooBar
{
   int x;
   int y;
}

Open in new window


I have a managed class which wraps the unmanaged class:
ref class Foo
{
   private FooBar* pFooBar;

   Foo()
   {
      pFooBar = new FooBar();
   }

   Foo()
   {
      delete pFooBar;
      pFooBar = nullptr;
   }
}

Open in new window



I have  a method which returns a handle to the managed class to a .Net C# client:
public Foo^  GetMeAFoo()
{
   Foo^ foo = gcnew Foo();
   return foo;
}

Open in new window


It's my understanding that since Foo is created on the managed heap that I do not have to explicitly
delete it. Garbage Collection (GC) on the managed side should take care of it.
The problem in my case is that the destructor of my managed class never seems to get called.
The results in the interior pointer to my unmanaged class getting (memory) leaked.

What is the correct way to handle this situation so that the underlying unmanaged class (FooBar) gets
correctly freed (when the managed wrapper class goes out of scope)?

Thanks,
JohnB
Avatar of jkr
jkr
Flag of Germany image

You're not deriving from IDisposable on the .NET side. That seems to be the problem to me...
ASKER CERTIFIED SOLUTION
Avatar of Jacques Bourgeois (James Burger)
Jacques Bourgeois (James Burger)
Flag of Canada image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
>>when the managed wrapper class goes out of scope)?

The problem is probably a lack of understanding.  The garbage collector will call a destructor when the class is removed from memory.  However the GC mechanism does not remove a class from memory when it goes out of scope - it removes it from memory when the memory is required again or when the app is closed.  This is not what one expects compared to unmanaged code - you do not have a memory leak.
you may consider to putting the creation of unmanaged objects into unmanaged code. the managed class then would only hold a 'handle' of the unmanaged object.

typedef FooBar * FBHDL;
class UnmanagedFooBarHandler
{
      std::vector<FooBar*> allbars;
      // private constructor makes it a singleton
      UnmanagedFooBarHandler() {}
      ~UnmanagedFooBarHandler() { while (allbars.size()) { delete allbars[0]; allbars.erase(allbars.begin()); }}
public:
      static UnmanagedFooBarHandler & UFBH() 
     { static UnmanagedFooBarHandler ufbh; return ufbh; }
     FBHDL createFooBar() { allbars.push_back(new FooBar()); return (FBHDL)allbars.back(); }
     void deleteFooBar(FBHDL fb) 
     { std::vector<FooBar*>::iterator f = std::find(allbars.begin(), allbars.end(), fb); 
       if (f != allbars.end()) { delete *f; allbars.erase(f); }
     }
     ...
};

Open in new window


the managed class would create FooBar via handler.

   
FBHDL fb = UFBH().createFooBar();

Open in new window


and delete it after use.

 
UFBH().deleteFooBar(fb);

Open in new window

 

Sara
Avatar of jxbma

ASKER

I added a finalize to the classes in question and all is well.