Writing memleak-free code in C++ isn't a problem for me, I just keep to the RAII idiom.
Writing memleak-free code in C# isn't very hard either, the garbage collector will handle it.
Unfortunately, writing C++/CLI code is a problem for me. I thought I had understood how it works, but I still have big problems and I hope you can give me some hints.
This is what I have:
A Windows service written in C# that uses C++ libraries (for example OpenCV) internally. The C++ classes are accessed with C++/CLI wrapper classes.
For example I have a MatW
C++/CLI wrapper class for a cv::Mat
image object, which takes as constructor argument a System::Drawing::Bitmap
:
public ref class MatW
{
public:
MatW(System::Drawing::Bitmap ^bmpimg)
{
cv::Size imgsize(bmpimg->Width, bmpimg->Height);
nativeMat = new Mat(imgsize, CV_8UC3);
// code to copy data from Bitmap to Mat
// ...
}
~MatW()
{
delete nativeMat;
}
cv::Mat* ptr() { return nativeMat; }
private:
cv::Mat *nativeMat;
};
Another C++ class might be for example
class PeopleDetector
{
public:
void detect(const cv::Mat &img, std::vector<std::string> &people);
}
And its wrapper class:
public ref class PeopleDetectorW
{
public:
PeopleDetectorW() { nativePeopleDetector = new PeopleDetector(); }
~PeopleDetectorW() { delete nativePeopleDetector; }
System::Collections::Generic::List<System::String^>^ detect(MatW^ img)
{
std::vector<std::string> people;
nativePeopleDetector->detect(*img->ptr(), people);
System::Collections::Generic::List<System::String^>^ peopleList = gcnew System::Collections::Generic::List<System::String^>();
for (std::vector<std::string>::iterator it = people.begin(); it != people.end(); ++it)
{
System::String^ p = gcnew System::String(it->c_str());
peopleList->Add(p);
}
return peopleList;
}
And here is the call to the method in my Windows Service C# class:
Bitmap bmpimg = ...
using (MatW img = new MatW(bmpimg))
{
using (PeopleDetectorW peopleDetector = new PeopleDetector())
{
List<string> people = peopleDetector.detect(img);
}
}
Now, here's my questions:
using
in my C# code? It makes the code ugly, when there are multiple wrapper objects in use, because the using
statements have to be nestedDispose()
instead after having used the objects?using
, no Dispose()
)List<string^>^
from C++/CLI to C#?gcnew
not mean that the garbage collector will take care of the objects and I don't have to care how and when to free them?I know that's a lot of questions, but all I want is to get rid of my memory leak, so I listed everything that I think could possibly go wrong...
What is Memory Leak in C/C++? The memory leak occurs, when a piece of memory which was previously allocated by the programmer. Then it is not deallocated properly by programmer. That memory is no longer in use by the program.
Memory leaks occur when new memory is allocated dynamically and never deallocated. In C programs, new memory is allocated by the malloc or calloc functions, and deallocated by the free function.
The only way to avoid memory leak is to manually free() all the memory allocated by you in the during the lifetime of your code. You can use tools such as valgrind to check for memory leaks. It will show all the memory that are not freed on termination of the program.
is there anything wrong with my code?
Not in what you've posted - you are applying using
statements correctly. So your code sample is not the cause of your memory leaks.
do I have to use using in my C# code? It makes the code ugly, when there are multiple wrapper objects in use, because the using statements have to be nested
You don't have to, but you don't have to nest them syntactically. This is equivalent:
Bitmap bmpimg = ...
using (MatW img = new MatW(bmpimg))
using (PeopleDetectorW peopleDetector = new PeopleDetector())
{
List<string> people = peopleDetector.detect(img);
}
could I use Dispose() instead after having used the objects?
You could, but then you'll need a try
/finally
to ensure Dispose
is always called, even when an exception is thrown. The using
statement encapsulates that whole pattern.
Could I just not bother and leave it to the garbage collector? (no using, no Dispose())
C++ RAII is commonly applied to all kinds of temporary state clean-up, including things like decrementing a counter that was incremented in the constructor, etc. Whereas the GC runs in a background thread. It is not suitable for all the deterministic clean-up scenarios that RAII can take care of. The CLR equivalent of RAII is IDisposable
, and the C# language interface to it is using
. In C++, the language interface to it is (naturally) destructors (which become Dispose
methods) and the delete
operator (which becomes a call to Dispose
). Ref class objects declared "on the stack" are really just equivalent to the C#
using pattern.
is the above code the right way to return objects like List^ from C++/CLI to C#?
Pretty much!
does using gcnew not mean that the garbage collector will take care of the objects and I don't have to care how and when to free them?
You don't have to free the memory. But if the class implements IDisposable
, then that is a totally separate issue from memory allocation. You have to call Dispose
manually before you abandon the object.
Be wary of finalizers - these are a way of hooking into the GC to get your own clean-up code to run when the GC collects your objects. But they are not really fit for general use in application code. They run from a thread that you don't control, at a time you don't control, and in an order that you don't control. So if one object's finalizer tries to access another object with a finalizer, the second object may already have been finalized. There is no way to control the ordering of these events. Most of the original uses of finalizers are nowadays covered by SafeHandle.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With