0

I'm trying to write a thin wrapper (of very little functionality that i actually need) around OpenCV 3 in C++/CLI to be consumed from C#.

However i'm not quite figuring out how i can store my Mat variables in the managed class, if i try to do it as is i get, as expected, an error stating that i can't mix native and non native members.

From what i gather i'm supposed to new up my native members and store a pointer to them, however i can't do that in all cases as a lot of OpenCV methods return a Mat and not a pointer to a Mat.

After some testing i saw that: - If i store a pointer to a new Mat(); this works just fine and it will still be available later on - If i try to store a pointer to a Mat (as returned by imread) it will be corrupted after the method ends.

What would be the proper way to store the Mat or a pointer to it?

Sample code:

    public ref class Matrix
    {
    private:
        Mat* mat;
        msclr::interop::marshal_context marshalcontext;
    public:
        static Matrix^ FromFile(System::String^ FileName)
        {
            Matrix^ ret = gcnew Matrix();               
            msclr::interop::marshal_context context;
            std::string StdFileName = context.marshal_as<std::string>(FileName);
            Mat tmpmat = imread(StdFileName);
            Mat * tmpmatptr = new Mat(50, 50, 1); // Works in all cases
                            //Mat * tmpmatptr = &tmpmat; // will NOT work out of the scope of this method
            Console::WriteLine(tmpmat.cols); // Always works
            Console::WriteLine(tmpmat.rows); // Always works
            Console::WriteLine(tmpmatptr->cols); // Always works
            Console::WriteLine(tmpmatptr->rows); // Always works
            ret->mat = tmpmatptr;
            return ret;
        }

        void Save(System::String^ FileName)
        {
            std::string StdFileName = marshalcontext.marshal_as<std::string>(FileName);
// Code bellow works if tmpmatptr in previous method was assigned a new Mat, doesn't work if it was assigned a pointer to imread result
            Console::WriteLine(mat->rows);
            Console::WriteLine(mat->cols);
            imwrite(StdFileName, *mat);
        }
    };

Note: i'm not looking for alternatives to writing my own wrapper, none of the ones i've tried were satisfactory.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Ronan Thibaudau
  • 3,413
  • 3
  • 29
  • 78
  • That is a standard [dangling pointer bug](https://en.wikipedia.org/wiki/Dangling_pointer). Use ret->mat = new Mat(tmpmat) to create a copy that's stored on the heap. Don't forget the destructor and the finalizer in Matrix, it needs to destroy it again. – Hans Passant Oct 18 '15 at 17:58

1 Answers1

1

You have a problem with scope. As soon as your function ends your mat is deconstructed and that memory is no longer valid. It works when you create it with new because the memory is then alive and on the heap until you call delete on it.

Particularly this call:

Mat * tmpmatptr = &tmpmat;

This sets tmpmatpr equal to the pointer of tmpmat which is on the current functions stack. At the end of the function all variables on the stack are destroyed.

I think what you're looking to change is this:

Mat tmpmat = imread(StdFileName);
Mat * tmpmatptr = new Mat(50, 50, 1);

to

Mat tmpmat = imread(StdFileName);
Mat * tmpmatptr = new Mat(tmpmat);
GDub
  • 544
  • 2
  • 7
  • 15
  • That did the trick, thank you so much. Am i correct in assuming that if it was another type, let's say type "testA" that didn't have a constructor there would be no way to store it at all across methods if it was only retrievable through a method that created it on the stack? Or is there a generic C++ way to do something like PromoteFromStackToHeap(myobj)? – Ronan Thibaudau Oct 18 '15 at 18:12
  • Anytime. Many well established c++ classes do have good copy constructor's, but many do not. There is a way, though it's very complex. In general you could use [std::memcpy](http://www.cplusplus.com/reference/cstring/memcpy/). This copies the raw memory data from object to another position. But I would consider this rather dangerous unless you absolutely know what you're doing with memory. – GDub Oct 18 '15 at 18:17