如何使用 std::vector 作为 C# 的参数调用非托管 C++ 函数?
Posted
技术标签:
【中文标题】如何使用 std::vector 作为 C# 的参数调用非托管 C++ 函数?【英文标题】:Howto call an unmanaged C++ function with a std::vector as parameter from C#? 【发布时间】:2010-09-22 17:46:39 【问题描述】:出于性能原因,我有一个 C# 前端和一个 C++ 后端。 现在我想调用一个 C++ 函数,例如:
void findNeighbors(Point p, std::vector<Point> &neighbors, double maxDist);
我想要的是一个 C# 包装函数,例如:
List<Point> FindNeigbors(Point p, double maxDist);
我可以将像 Point[] 这样的平面数组传递给非托管 C++ dll,但问题是,我不知道要分配多少内存,因为我不知道函数将返回的元素数量...
有没有一种优雅的方法来处理这个问题而不会出现内存泄漏问题?
感谢您的帮助!
本杰明
【问题讨论】:
【参考方案1】:这里最好的解决方案是用 C 编写一个包装函数,该函数仅限于非 C++ 类。非平凡的 C++ 类本质上是不可通过 PInvoke 层 [1] 进行编组的。而是让包装函数使用更传统的 C 签名,这很容易针对 PInvoke 进行攻击
void findNeigborsWrapper(
Point p,
double maxDist,
Point** ppNeighbors,
size_t* pNeighborsLength)
[1] 是的,在某些情况下您可以侥幸逃脱,但这是例外而非规则。
【讨论】:
【参考方案2】:阻抗不匹配严重。你必须用 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++ 编写算法时可能获得的性能优势。
【讨论】:
【参考方案3】:为了减少复制的开销(如果确实会导致性能问题),可以围绕 std::vector 编写 C++/CLI 引用类。这样,c++ 算法就可以在 c++ 类型上工作,而 C# 代码可以访问相同的数据而无需过度复制。
C++/CLI 类可以实现 operator[] 和 Count 以避免依赖 IEnumerable::GetEnumerator ()。
【讨论】:
【参考方案4】:或者用 C++/CLI 编写你的包装器。让它采用符合 CLS 的类型,例如 IEnumerable,然后(叹气)将每个元素复制到您的向量中,然后调用 PInvoke。
【讨论】:
以上是关于如何使用 std::vector 作为 C# 的参数调用非托管 C++ 函数?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Python 列表在 C++ 中使用 SWIG 分配 std::vector?
Swig:将 std::vector<unsigned char> 传递给从 c++ 生成的 c# 函数
将 std::vector 作为 numpy 数组返回给 python