MATLAB: Can we use matlab engine from a inside a function in C++

cenginefunction

I compiled a C++ program to sort double values(matlab does the sorting). it works fine. however when i move the code related to matlab computation to a function, it gives erroneous results.
following is the code with both the formats in a single file. when i execute matlab functions from main it works, when i execute the matlab part from a function(call_matlab_processing) it gives random results.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "engine.h"
#include <iostream>
#include <vector>
#define BUFSIZE 256
int call_matlab_processing(double double_array[], int size_double_array,double * sorted, double * indices_cpp)
{
for (int i=0;i<size_double_array;i++)
{
std::cout << "double array at "<< i << " "<< double_array[i]<<std::endl;
}
Engine *ep;
mxArray *T = NULL, *result = NULL, *indices=NULL;
/*
* Call engOpen with a NULL string. This starts a MATLAB process
* on the current host using the command "matlab".
*/
if (!(ep = engOpen(""))) {
fprintf(stderr, "\nCan't start MATLAB engine\n");
return 1;
}
T = mxCreateDoubleMatrix(1,size_double_array, mxREAL);
memcpy((void *)mxGetPr(T), (void *)double_array, sizeof(double_array));
/** Place the variable T into the MATLAB workspace */
engPutVariable(ep, "T", T);
engEvalString(ep, "[D I] = sort(T,'descend')");
engEvalString(ep, "dlmwrite('myFile.txt',D)");
result = engGetVariable(ep,"D");
indices = engGetVariable(ep,"I");
sorted=(double *)mxGetData(result);
indices_cpp=(double *)mxGetData(indices);
/* for (int i=0;i<10;i++)
{
std::cout << "sorted= " <<*sorted << " indices= " << *indices_cpp <<std::endl;
sorted++;
indices_cpp++;
}*/
mxDestroyArray(T);
mxDestroyArray(result);
mxDestroyArray(indices);
engEvalString(ep, "close;");
engClose(ep);
return 0;
}
int main()
{
int size_double_array=10;
double double_array[10]={ 0, 5, 2, 7, 3, 9, 1, 6, 8, 4 };
double * sorted;
double * indices_cpp;
Engine *ep;
mxArray *T = NULL, *result = NULL, *indices=NULL;
if (!(ep = engOpen(""))) {
fprintf(stderr, "\nCan't start MATLAB engine\n");
return 1;
}
T = mxCreateDoubleMatrix(1,size_double_array, mxREAL);
memcpy((void *)mxGetPr(T), (void *)double_array, sizeof(double_array));
engPutVariable(ep, "T", T);
engEvalString(ep, "[D I] = sort(T,'descend')");
engEvalString(ep, "dlmwrite('myFile.txt',D)");
result = engGetVariable(ep,"D");
indices = engGetVariable(ep,"I");
sorted=(double *)mxGetData(result);
indices_cpp=(double *)mxGetData(indices);
mxDestroyArray(T);
mxDestroyArray(result);
mxDestroyArray(indices);
engEvalString(ep, "close;");
engClose(ep);
// int result=call_matlab_processing(double_array,10,sorted,indices_cpp);
for (int i=0;i<10;i++)
{
std::cout << "sorted= " <<*sorted << " indices= " << *indices_cpp <<std::endl;
sorted++;
indices_cpp++;
}
std::cout << "Done"<< std::endl;
return EXIT_SUCCESS;
}

Best Answer

You have a fundamental flaw in your code. You free the memory behind the pointers that you use downstream in your code. E.g.,
result = engGetVariable(ep,"D"); // <-- Creates the mxArray result, including the data area
indices = engGetVariable(ep,"I"); // <-- Creates the mxArray indices, including the data area
sorted=(double *)mxGetData(result); // <-- Gets pointer to data area of result
indices_cpp=(double *)mxGetData(indices); // <-- Gets pointer to data area of indices
mxDestroyArray(T);
mxDestroyArray(result); // <-- Wipes out result, *and* the memory behind sorted
mxDestroyArray(indices); // <-- Wipes out indices, *and* the memory behind indices_cpp
// So at this point in the code, both of the pointers sorted and indices_cpp are *invalid*
engEvalString(ep, "close;");
engClose(ep);
// Code downstream of here uses *invalid* pointers. Anything can happen.
// Could get lucky good results, or random bad results, or even a program bomb.
// int result=call_matlab_processing(double_array,10,sorted,indices_cpp);
for (int i=0;i<10;i++)
{
std::cout << "sorted= " <<*sorted << " indices= " << *indices_cpp <<std::endl;
sorted++;
indices_cpp++;
}
You need to delay executing these two lines until after you are done using their data areas:
mxDestroyArray(result);
mxDestroyArray(indices);