如何使用st#:: vector作为C#参数调用非托管C ++函数?

出于性能原因,我有一个C#前端和一个C ++后端。 现在我想调用一个C ++函数,例如:

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

我想要的是一个C#包装函数,如:

 List FindNeigbors(Point p, double maxDist); 

我可以将像Point []这样的平面数组传递给非托管C ++ dll,但问题是,我不知道要分配多少内存,因为我不知道函数将返回的元素数量…

是否有一种优雅的方式来处理这个没有内存泄漏的麻烦?

谢谢你的帮助!

本杰明

这里最好的解决方案是在C中编写一个包装函数,该函数仅限于非C ++类。 通过PInvoke层[1],非平凡的C ++类基本上是不可复制的。 相反,包装函数使用更传统的C签名,这很容易被PInvoke反对

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

[1]是的,在某些情况下,你可以逃脱它,但这是例外,而不是规则。

阻抗不匹配很严重。 您必须使用C ++ / CLI语言编写包装器,以便可以构造向量。 另一个问题是Point,你的C ++声明与它的托管版本不兼容。 您的代码应该与此类似,将其添加到CLR节点的类库项目中。

 #include  using namespace System; using namespace System::Collections::Generic; struct Point { int x; int y; }; void findNeighbors(Point p, std::vector &neighbors, double maxDist); namespace Mumble { public ref class Wrapper { public: List^ FindNeigbors(System::Drawing::Point p, double maxDist) { std::vector neighbors; Point point; point.x = pX; point.y = pY; findNeighbors(point, neighbors, maxDist); List^ retval = gcnew List(); for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) { retval->Add(System::Drawing::Point(it->x, it->y)); } return retval; } }; } 

请注意复制集合的成本,这可以快速消除您在本机C ++中编写算法时可能获得的优势。

为了减少复制的开销(如果确实会导致性能问题),可以围绕std :: vector <>编写C ++ / CLI ref类。 这样,c ++算法可以处理c ++类型,C#代码可以访问相同的数据而无需过多的复制。

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

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