Как вызвать неуправляемую функцию C ++ с std :: vector в качестве параметра из C #? - PullRequest
2 голосов
/ 22 сентября 2010

У меня есть интерфейс C # и сервер C ++ по соображениям производительности.Теперь я хотел бы вызвать функцию C ++, например:

void findNeighbors(Point p, std::vector<Point> &neighbors, double maxDist);

. Я хотел бы иметь функцию-оболочку C #, такую ​​как:

List<Point> FindNeigbors(Point p, double maxDist);

.массив как Point [] для неуправляемой C ++ dll, но проблема в том, что я не знаю, сколько памяти выделить, потому что я не знаю, сколько элементов вернет функция ...

Есть ли элегантный способ справиться с этим без проблем с утечками памяти?

Спасибо за вашу помощь!

Бенджамин

Ответы [ 4 ]

3 голосов
/ 22 сентября 2010

Лучшее решение здесь - написать функцию-обертку на C, которая ограничена классами не-C ++.Нетривиальные классы C ++ по существу не маршируются через слой PInvoke [1].Вместо этого сделайте так, чтобы функция-обертка использовала более традиционную сигнатуру C, которую PInvoke легко использовать против

void findNeigborsWrapper(
  Point p,
  double maxDist, 
  Point** ppNeighbors,
  size_t* pNeighborsLength)

[1] Да, есть определенные случаи, когда с этим можно сойти, но это исключение, а не правило.

1 голос
/ 22 сентября 2010

Чтобы уменьшить накладные расходы при копировании (если это вызывает проблемы с производительностью), можно было бы написать класс ссылок C ++ / CLI вокруг std :: vector <>.Таким образом, алгоритм c ++ может работать с типами c ++, а код C # может обращаться к одним и тем же данным без чрезмерного копирования.

Класс C ++ / CLI может реализовывать operator [] и Count, чтобы избежать использования IEnumerable :: GetEnumerator().

1 голос
/ 22 сентября 2010

Несоответствие импеданса является серьезным. Вы должны написать оболочку на языке C ++ / CLI, чтобы вы могли создать вектор. Дополнительной проблемой является Point, ваша декларация C ++ для нее не совместима с управляемой версией. Ваш код должен напоминать это, добавьте его в проект библиотеки классов с узла CLR.

#include <vector>

using namespace System;
using namespace System::Collections::Generic;

struct Point { int x; int y; };
void findNeighbors(Point p, std::vector<Point> &neighbors, double maxDist);

namespace Mumble {

    public ref class Wrapper
    {
    public:
        List<System::Drawing::Point>^ FindNeigbors(System::Drawing::Point p, double maxDist) {
            std::vector<Point> neighbors;
            Point point; point.x = p.X; point.y = p.Y;
            findNeighbors(point, neighbors, maxDist);
            List<System::Drawing::Point>^ retval = gcnew List<System::Drawing::Point>();
            for (std::vector<Point>::iterator it = neighbors.begin(); it != neighbors.end(); ++it) {
                retval->Add(System::Drawing::Point(it->x, it->y));
            }
            return retval;
        }
    };
}

Обратите внимание на стоимость копирования коллекции, это может быстро стереть преимущество, которое вы можете получить от написания алгоритма на нативном C ++.

0 голосов
/ 22 сентября 2010

Или напишите свою обертку в C ++ / CLI. Пусть он принимает CLS-совместимый тип, такой как IEnumerable, и затем (вздох) копирует каждый элемент в ваш вектор, а затем вызывает PInvoke.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...