2010-09-22 60 views
2

出于性能原因,我有一个C#前端和一个C++后端。 现在我想调用C++之类的函数,例如:Howto使用std :: vector作为C#参数调用非托管C++函数?

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

我想有像一个C#包装函数:

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

我能通过一个平面数组像点[]到非托管的C++ DLL,但问题是,我不知道分配多少内存,因为我不知道函数将返回的元素数量...

有没有一个优雅如何处理这个问题,而不会造成内存泄漏问题?

感谢您的帮助!

本杰明

回答

3

最好这里的解决方案是用C来写一个包装函数被限制于非C++类。非平凡的C++类实质上是通过PInvoke层[1]不可编组的。相反,具有包装功能使用更传统的C签名这是很容易的PInvoke对

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

[1]是有一定的情况下,你可以摆脱它,但是这是例外,而不是规则。

1

阻抗不匹配很严重。你必须用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; 
     } 
    }; 
} 

请注意复制收集成本,这可以快速擦除PERF优势,你可能会失去在编写本地C++的算法。

0

或者用C++/CLI编写你的包装器。让它采用符合CLS的类型(如IEnumerable),然后(叹气)将每个元素复制到您的矢量中,然后调用PInvoke。

0

为了减少从复制的开销(如果这样做会导致性能问题)将有可能写周围STD一个C++/CLI引用类::矢量<>。这样C++算法可以在C++类型上工作,并且C#代码可以访问相同的数据而不会过度复制。

C++/CLI类可以实现operator []和Count以避免依赖于IEnumerable :: GetEnumerator()。

相关问题