Написание кода без C ++ на C ++ не проблема для меня, я просто придерживаюсь RAII идиома.
Написание кода без утечек в C # тоже не сложно, сборщик мусора справится с этим.
К сожалению, написание кода C ++ / CLI является проблема для меня. Я думал, что понял, как это работает, но у меня все еще есть большие проблемы, и я надеюсь, что вы можете дать мне несколько советов.
Вот что у меня есть:
Служба Windows, написанная на C #, которая использует библиотеки C ++ (например, OpenCV) для внутреннего использования. Доступ к классам C ++ осуществляется с помощью классов-оболочек C ++ / CLI.
Например, у меня есть MatW
Класс C ++ / CLI для cv::Mat
объект изображения, который принимает в качестве аргумента конструктора 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;
};
Другой класс C ++ может быть, например,
class PeopleDetector
{
public:
void detect(const cv::Mat &img, std::vector<std::string> &people);
}
И его класс оболочки:
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;
}
И вот вызов метода в моем классе Windows Service C #:
Bitmap bmpimg = ...
using (MatW img = new MatW(bmpimg))
{
using (PeopleDetectorW peopleDetector = new PeopleDetector())
{
List<string> people = peopleDetector.detect(img);
}
}
Теперь вот мои вопросы:
using
в моем коде C #? Это делает код некрасивым, когда используется несколько объектов-оболочек, потому что using
заявления должны быть вложеннымиDispose()
вместо того, чтобы после использования объектов?using
нет Dispose()
)List<string^>^
из C ++ / CLI в C #?gcnew
не означает, что сборщик мусора позаботится об объектах, и мне не нужно заботиться о том, как и когда их освободить?Я знаю, что это много вопросов, но все, что я хочу, это избавиться от утечки памяти, поэтому я перечислил все, что, по моему мнению, могло пойти не так …
что-то не так с моим кодом?
Не в том, что вы опубликовали — вы подаете заявку using
заявления правильно. Таким образом, ваш пример кода не является причиной утечек памяти.
я должен использовать использование в моем коде C #? Это делает код некрасивым, когда используется несколько объектов-оболочек, потому что операторы using должны быть вложенными
Вы не должны, но вам не нужно вкладывать их синтаксически. Это эквивалентно:
Bitmap bmpimg = ...
using (MatW img = new MatW(bmpimg))
using (PeopleDetectorW peopleDetector = new PeopleDetector())
{
List<string> people = peopleDetector.detect(img);
}
Могу ли я использовать Dispose () вместо того, чтобы использовать объекты?
Вы могли бы, но тогда вам понадобится try
/finally
для обеспечения Dispose
всегда вызывается, даже когда выдается исключение. using
заявление инкапсулирует весь этот шаблон.
Могу я просто не беспокоиться и оставить это сборщику мусора? (без использования, без утилизации ())
C ++ RAII обычно применяется для всех видов временной очистки состояния, включая такие вещи, как уменьшение счетчика, который был увеличен в конструкторе, и т. Д. В то время как сборщик мусора работает в фоновом потоке. Это не подходит для всех детерминированных сценариев очистки, о которых может позаботиться RAII. CLR-эквивалент RAII IDisposable
и интерфейс языка C # к нему using
, В C ++ языковой интерфейс к нему является (естественно) деструкторами (которые становятся Dispose
методы) и delete
оператор (который становится вызовом Dispose
). Объекты класса Ref, объявленные «в стеке», на самом деле просто эквивалентны C#
используя шаблон.
является ли приведенный выше код правильным способом возврата объектов типа List ^ из C ++ / CLI в C #?
Довольно много!
Разве использование gcnew не означает, что сборщик мусора позаботится об объектах, и мне не нужно заботиться о том, как и когда их освобождать?
Вам не нужно освобождать память. Но если класс реализует IDisposable
тогда это совершенно отдельная проблема с распределением памяти. Вы должны позвонить Dispose
вручную, прежде чем покинуть объект.
Будьте осторожны с финализаторами — это способ подключиться к GC, чтобы ваш собственный код очистки запускался, когда GC собирает ваши объекты. Но они не очень подходят для общего использования в коде приложения. Они запускаются из потока, который вы не контролируете, в то время, когда вы не контролируете, и в порядке, который вы не контролируете. Таким образом, если финализатор одного объекта пытается получить доступ к другому объекту с помощью финализатора, второй объект, возможно, уже был завершен. Нет способа контролировать порядок этих событий. Большинство оригинальных применений финализаторов в настоящее время покрыты SafeHandle.
У вас нет финализатора в классе ref.
В C ++ / CLI деструкторы вызываются либо когда вы создаете экземпляр класса в стеке (стиль C ++), а затем он выходит из области видимости, либо вы используете delete
оператор.
Финализаторы называются GC когда пришло время завершать объект.
В C # GC обрабатывает уничтожение всех объектов (нет оператора удаления), поэтому нет разницы между деструктором и финализатором.
Итак «деструкторы«с ~ ведут себя как деструкторы c ++, совсем не как деструкторы C #.
«деструкторы«в C ++ / CLI класс ссылки скомпилированы в .Net Dispose()
метод.
Эквивалент для деструктора / финализатора C # — это метод финализатора, который определяется с помощью ! (восклицательный знак).
Итак, чтобы избежать утечек памяти, вам нужно определить финализатор:
!MatW()
{
delete nativeMat;
}
~MatW()
{
this->!MatW();
}
Смотрите статью MSDN Деструкторы и финализаторы в Visual C ++
Использовать