How can I call MATLAB object's method from C++?

Hi
Using bellow command we can easily call a function(here "foo.m") which was wrote in MATLAB from C++.
mexCallMATLAB(nlhs, plhs, nrhs, prhs, "foo")
But what if "foo" is a method of a class?
classdef Foo < handle
...
function out = foo(obj, in)
end
end
Is there any straightforward or trick to call member function from C++?

 Accepted Answer

Call it just like a normal function with your Foo object as the input argument. E.g., if you have an object of class Foo at the m-file level:
x = Foo(whatever);
Then pass it into a mex routine:
Foo_mex(x);
Inside the Foo_mex.c file you would have something like this:
int i;
if( nrhs ) {
i = mexCallMATLAB(0,NULL,1,prhs,"foo");
:
etc

13 Comments

Hi James
Thanks for your answer. I passed an instance of Foo class to my mexCallMATLAB location and set it as first element of prhs. But I got the following error
No Static method 'foo' in class 'Foo'.
Why it think that foo must be a static method since I set first element of prhs with object instance?
What I have posted above worked fine for me. Please post your classdef code, the m-code you are using to call the mex function, and the C code of your mex function.
James I observe that when I get the MATLAB object instance in mexFunction then immediately I can call its method from C++. But later (when its data is provided actually) calling the same as before make the following error.
No Static method 'foo' in class 'Foo'.
It seems that the instance of class 'Foo' for the second call is not valid(changed or whatever) which MATLAB doesn't recognize it as a 'Foo' instance and it looks for a static method with that name.
Following is the pseudo-code. Suppose we have a CPP class as follows:
#include <mex.h>
class CPP_CLASS{
public:
mxArray * obj;
bool call_MATLAB_func(string function_name);
};
and a .cpp file for mex as follows
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
...
if (!strcmp("SaveMATLABInstance", cmd))
{
//save the instance
cpp_class.obj = (mxArray *)prhs[1];
// here I call the method with above instance immediately
// and it works well as you said
cpp_class.call_MATLAB_func('matlab_method');
return;
}
}
The above code works well. But after that and some where else calling following method caused mentioned error.
void main() {
...
cpp_class.call_MATLAB_func('matlab_method');
}
Since the last is the second call, I can sure that obj was set successfully before(since first call was done). Also the calling 'mexCallMATLAB' syntax is right(since it is same as first call and its implementation is in the 'call_MATLAB_func' method).
So as the MATLAB seeks for a Static method I guess that the instance is not valid anymore... But also I am sure that it is not destructed yet and is alive as before...
bool call_MATLAB_func(string function_name)
{
int nlhs = 0, nrhs = 2;
mxArray *plhs[1], *prhs[2];
prhs[0] = this->obj;
prhs[1] = mxCreateLogicalScalar(false);
if (mexCallMATLAB(nlhs, plhs, nrhs, prhs, function_name))
{
std::cout << "mexCallMATLAB failed" << std::endl;
return false;
}
return true;
}
What is my mistake? Is it possible that an object instance(handle) change during its generation/life? Or there is something else? Thanks for your help.
Don't show pseudocode. Please show an actual example, perhaps a simplified version of what you're doing, because the problem could lie in the specific details of your example that are lost when you abstract it into pseudocode.
Bellow is the actual code...
The C++ method
bool MatlabModuleInterface::Start()
{
int nlhs = 0, nrhs = 5;
mxArray *plhs[1], *prhs[5];
prhs[0] = MatlabModuleInterface::GetInstance().obj;
prhs[1] = mxCreateLogicalScalar(false);
prhs[2] = mxCreateLogicalScalar(false);
prhs[3] = mxCreateLogicalScalar(false);
prhs[4] = mxCreateLogicalScalar(false);
if (mexCallMATLAB(nlhs, plhs, nrhs, prhs, "callback"))
{
std::cout << "mexCallMATLAB failed" << std::endl;
return false;
}
return true;
}
The mex method
#include "mex.h"
#include "class_handle.hpp"
#include "MatlabModuleInterface.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
...
if (!strcmp("SaveMatlabInstance", cmd))
{
// Check parameters
if (nlhs < 0 || nrhs != 2)
{
mexErrMsgTxt("Unexpected arguments.");
}
MatlabModuleInterface::GetInstance().obj = (mxArray *)prhs[1];
MatlabModuleInterface::GetInstance().Start();
return;
}
// Got here, so command not recognized
mexErrMsgTxt("Command not recognized.");
}
The third one is the command that somewhere I call 'MatlabModuleInterface::GetInstance().Start()' again(first call is the call inside 'SaveMatlabInstance'). Also I am sure that the 'obj' still alive.
The error:
Error using Wrapper/callback
No Static method 'callback' in class 'Wrapper'.
Thanks
Bonje Fir
Bonje Fir on 18 Oct 2017
Edited: Bonje Fir on 18 Oct 2017
I just simplify the 'MatlabModuleInterface' which uses Singleton design pattern. Moreover, the call inside 'SaveMatlabInstance' is just as a test for functionality of Start and will be removed if problem solved.
Can you post your C++ class code you are using for the Singleton design pattern? Maybe something is amiss in how you are setting this up and using it in your code.
Also, I would point out that your code design for this is inherently unstable. You are relying on the obj address to remain valid throughout your calls. But MATLAB variables can shift around in memory as you change them at the m-code level. You don't have direct control over this. The only thing you can do is to try not to do any operation that would cause the variable to shift locations in memory, in hopes that it will stay put and not bomb your mex routine at the next call.
James thanks for your detailed answers.
I think the point is this: ...But MATLAB variables can shift around in memory as you change them at the m-code level...
For some standalone modules my routine is like this:
0) I initialize module class completely (in MATLAB)
1) The module processes data and send its outputs via
MatlabModuleInterface wrapper to others(modules) every time
it provided them(processing loop at m-code level).
2) Others(modules) outputs must deliver to module(asynchronously i.e
every time they have such outputs. module at this time
is busy with step(1) and done successfully step(0))
via MatlabModuleInterface wrapper.
*NOTE:* So at first(i.e after step(0) and before step(1))
I send an instance of module class to MatlabModuleInterface(i.e 'obj')
which every time it wants(i.e data received) call module's
callback on that instance...
Review: The problem I was faced was this: How can I call MATLAB class member function? Answer: You can if you have instance of it(easily put it as the first argument). Therefore I sent an instance 'obj' right after step(0) to MatlabModuleInterface and it stores that for further use.
But as you said above this is true until the instance not changed(shift around via MATLAB). Moreover, this(shift around) can happen just with changes in instance variables values and so on which is frequently occur in step(1) loop!
Conclusion: Therefore step(2)(which runs async with step(1)) could fail.
Is this true or I am misunderstood?
PS: At the bellow code the instance at memory is '0797F9D8' and it is fixed in whole of the test. But if the class was more complicated(more properties) then changing in its properties may cause changing in '0797F9D8' value?
Bonje Fir
Bonje Fir on 19 Oct 2017
Edited: Bonje Fir on 19 Oct 2017
I am a little confused.
...as you change them at the m-code level... is this change mean something like change in its properties values? or is something more?
...The only thing you can do is to try not to do any operation that would cause the variable to shift locations in memory... What operations exactly? It has several properties and classes which change its values and even its classes may constructed, fulfilled with new values or destroyed... Are these operations may cause shift instance in memory? or you mean something more like deleting class(like 'clear F')? I can say that the instance is alive, not destroyed... class not cleared...
"I am a little confused."
Welcome to the club. The details of this aspect of the MATLAB Memory Manager are not published. So the only thing us users can do is make educated guesses as to how & when things like this happen.
IF the only thing you are doing is changing properties of the class object at the m-code level, and not creating or assigning anything to the object as a whole, then my guess is that the object mxArray header will remain at its original memory location. So in this case your code would probably be OK and not bomb. In fact, this is precisely what I do with my example. Everything is OK as long as I only change the property x value ... the mxArray header stays put in memory. It is only when I delete the variable itself, rendering the obj address in the mex routine invalid, that I run into problems with my example.
So, what can you do? Just be aware of this shortcoming of your mex code design, and be very careful with what you do at the m-code level. Clearing the variable or an assignment operation of the whole variable will almost certainly be trouble at some point. An assignment operation of only the properties will probably not be trouble (but caveat emptor since these rules are not published). The alternative would be to abandon your approach of storing the obj address in the mex routine, and always require that the caller pass in the obj.
Thanks James. Many useful information which cleared the problem.
I put several 'Set' call to my m-code and in every assignment a comparison with previous value of 'obj'(i.e what we saved in MatlabModuleInterface class previously). summary:
At the first call MatlabModuleInterface::obj is NULL which is normal.
obj 0000000000000000
mxArray: 000000005A1C6940
Next time I call 'Set'
obj 000000005A1C6940
mxArray: 000000005A1C69B0
another call
obj 000000005A1C69B0
mxArray: 000000005A1C5BB0
another one
obj 000000005A1C5BB0
mxArray: 000000005A1C6400
We can see each time I call 'Set' the previous value of 'obj' is expired!
About your suggestions. The above log happened even I commented most of module's code and it just do simple tasks like properties assignments addition to pass primitive data using mexFunction. Moreover, your last point is not operational in this case. Since this call is asynchronous I do not know when I must update 'obj'(i.e when data received from other modules we must call 'obj's method and this time is unknown for module therefore I cannot update 'obj' before it).
Hmmm ... I am curious. What are you doing at the caller level that is apparently invalidating your obj address? Can you post your "simple" code? (i.e. the complete m-code + C-code). I would like to understand why this is happening.
Hi James I think it is not a readable code... .
classdef Module < ModuleInterface
properties
% some primitive variables
% ...
% some variables for GUI inf
GraphicManager
GUI
GUIVars
GUILink
end
methods
function obj = module(moduleName, addressPort)
% Inheritance(module is c++ wrapper. it send moduleName or addressport to c++)
obj = obj@ModuleInterface(moduleName, addressPort);
obj.Done = false;
obj.Started = false;
% fileName, handles: came from gui
global GUILink
%----------- make initial variables
GUILink = module.guiLink;
GUILink.RunFlag = false; % not ran yet
GUILink.ResetFlag = false;
%--- load last gui setting
GUILink.loadLastGUISetting;
%
addlistener(GUILink,'UserChangedInputFile',@(src, event)manageGUIEvents(obj,'UserChangedInputFile',src,event));
addlistener(GUILink,'UserResetGUI',@(src,event)manageGUIEvents(obj,'UserResetGUI',src,event));
%----------- run gui
addpath(genpath('gui'));
main; % make gui handles
%-------------------
obj.GUILink = GUILink;
obj.GUI = GUILink.handles;
obj.Time = 0;
% went to config file
obj.GUIVars.LastUpdate = -inf;
%------ read config and setting
fid = fopen('+module\config.txt','r');
aux.std_file2obj(obj,fid)
fclose(fid);
obj.GraphicManager = module.customGraphicManager;
end
%%Init
function varargout = Init(obj, varargin)
% Container is a MATLAB class which uses mex to send data via it.
% - i.e the actual class is a c++ class and Container.m just
% - send its data to it.
obj.config = Container('Config', 'module');
obj.data = Container('Data', 'servo');
end
function varargout = Process(obj, varargin)
d = .1;
while ~obj.Done
% processing data and generating output
obj.data.speed = obj.data.speed + d;
obj.data.angle = obj.data.angle + d;
pause(10);
obj.send(obj.data);
end
end
%%-------- other public methods
%%Here is the callback which if data received it must called via a Container type as its input
module_callback(obj, data);
%%other methods
setMessage(obj , Data , Type)
setModuleInfoMessage(obj)
%%send obj output via mex. its implementation is in ModuleInterface
send(obj, data);
end
%------
methods(Access = protected)
manageEvents(obj,eventName,src,event)
manageGUIEvents(obj,eventName,src,event)
[ValidID] = checkID(obj,newID);
function [newID] = getNewID(obj)
newID = max(obj.IDList)+1;
end
resetGUI(obj)
end
methods(Access = public)
updateGUI(obj)
end
end
ModuleInterface.m has a ModuleInterface_mex.cpp and Container.m has a Container_mex.cpp. They(i.e .m classes) just wrap data to their cpp files and the data store there or send to other modules.
The problem is when the 'data' comes from outside to module(ModuleInteface_mex.cpp), it must call module_callback(obj, data) from ModuleInterface_mex.cpp[i.e mexCallMATLAB(nlhs, plhs, nrhs, prhs, module_callback)]...

Sign in to comment.

More Answers (1)

Here is some code based loosely on your singleton design, with an example run. Note that if you clear the mex routine, then the obj address is of course lost and you must re-set it. Maybe you are clearing your mex routine between calls inadvertently?
#include "mex.h"
class MatlabModuleInterface
{
public:
mxArray *obj;
static MatlabModuleInterface& GetInstance()
{
static MatlabModuleInterface instance;
return instance;
}
bool MatlabModuleInterface::Display()
{
int nlhs = 0, nrhs = 1;
mxArray *plhs[1], *prhs[1];
prhs[0] = MatlabModuleInterface::GetInstance().obj;
mexPrintf("Using obj = %p\n",prhs[0]);
if( mexCallMATLAB(nlhs, plhs, nrhs, prhs, "foo_disp") ) {
mexErrMsgTxt("mexCallMATLAB foo_disp failed");
}
return true;
}
bool MatlabModuleInterface::Set(mxArray *mx)
{
int nlhs = 0, nrhs = 2;
mxArray *plhs[1], *prhs[2];
prhs[0] = MatlabModuleInterface::GetInstance().obj;
prhs[1] = mx;
mexPrintf("Using obj = %p\n",prhs[0]);
if( mexCallMATLAB(nlhs, plhs, nrhs, prhs, "foo_set") ) {
mexErrMsgTxt("mexCallMATLAB foo_set failed");
}
return true;
}
};
int firstcall = 1;
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
if( firstcall ) {
if( nrhs == 0 ) {
mexErrMsgTxt("Need one input of class Foo on 1st call.");
}
firstcall = 0;
mexPrintf("Setting obj = %p\n",prhs[0]);
MatlabModuleInterface::GetInstance().obj = (mxArray *)prhs[0];
return;
}
if( nrhs ) {
MatlabModuleInterface::GetInstance().Set((mxArray *)prhs[0]);
} else {
MatlabModuleInterface::GetInstance().Display();
}
}
The Foo class is:
classdef Foo < handle
properties
x
end
methods
function foo_disp(obj)
fprintf('The current value of x = %f\n',obj.x);
end
function foo_set(obj,y)
obj.x = y;
end
end
end
And a sample run is:
>> F = Foo
F =
Foo handle
Properties:
x: []
Methods, Events, Superclasses
>> singleton_design
??? Error using ==> singleton_design
Need one input of class Foo on 1st call.
>> singleton_design(F)
Setting obj = 0797F9D8
>> singleton_design
Using obj = 0797F9D8
The current value of x =
>> F.x = 5
F =
Foo handle
Properties:
x: 5
Methods, Events, Superclasses
>> singleton_design
Using obj = 0797F9D8
The current value of x = 5.000000
>> singleton_design(7)
Using obj = 0797F9D8
>> singleton_design
Using obj = 0797F9D8
The current value of x = 7.000000
>> clear singleton_design
>> singleton_design
??? Error using ==> singleton_design
Need one input of class Foo on 1st call.
>> singleton_design(F)
Setting obj = 0797F9D8
>> singleton_design
Using obj = 0797F9D8
The current value of x = 7.000000
>> clear F
>> singleton_design
Using obj = 0797F9D8
??? Error using ==> singleton_design
Undefined function or method 'foo_disp' for input arguments of type 'char'.
For that last singleton_design call, the obj address within the MatlabModuleInterface class is invalid, and anything could have happened including a MATLAB crash. This is an example of the inherent instability of the C code design ... you are relying on the Foo variable address contained in obj to remain valid and hope that the user doesn't do anything to make it invalid.

Categories

Tags

Asked:

on 8 Oct 2017

Commented:

on 22 Oct 2017

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!