Howto call an unmanaged C++ function with a std::vector as parameter from C#?

前端 未结 4 997
孤街浪徒
孤街浪徒 2020-12-12 01:04

I have a C# front end and a C++ backend for performance reasons. Now I would like to call a C++ function like for example:

void findNeighbors(Point p, std::v         


        
相关标签:
4条回答
  • 2020-12-12 01:10

    Or write your wrapper in C++/CLI. Have it take a CLS-compliant type such as IEnumerable and then (sigh) copy each element into your vector, then call the PInvoke.

    0 讨论(0)
  • 2020-12-12 01:24

    The best solution here is to write a wrapper function in C which is limited to non-C++ classes. Non-trivial C++ classes are essentially unmarshable via the PInvoke layer [1]. Instead have the wrapper function use a more traditional C signature which is easy to PInvoke against

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

    [1] Yes there are certain cases where you can get away with it but that's the exception and not the rule.

    0 讨论(0)
  • 2020-12-12 01:28

    In order to reduce overhead from copying (if that does cause performance problems) it would be possible to write a C++/CLI ref class around std::vector<>. That way the c++ algorithm can work on c++ types and C# code can access the same data without excessive copying.

    The C++/CLI class could implement operator[] and Count in order to avoid relying on IEnumerable::GetEnumerator ().

    0 讨论(0)
  • 2020-12-12 01:29

    The impedance mismatch is severe. You have to write a wrapper in the C++/CLI language so that you can construct a vector. An additional problem is Point, your C++ declaration for it is not compatible with the managed version of it. Your code ought to resemble this, add it to a class library project from the CLR node.

    #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;
            }
        };
    }
    

    Do note the cost of copying the collection, this can quickly erase the perf advantage you might get out of writing the algorithm in native C++.

    0 讨论(0)
提交回复
热议问题