Ronan Thibaudau
Ronan Thibaudau

Reputation: 3603

Storing native data in C++/cli without using new

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.

Upvotes: 0

Views: 166

Answers (1)

GDub
GDub

Reputation: 638

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);

Upvotes: 1

Related Questions