Editor's Note: This file was selected as MATLAB Central Pick of the Week
This package provides an example of how to wrap a C++ class in a MATLAB class, via a mex interface, safely, without memory leaks, whilst achieving an interface in MATLAB that is similar to the underlying C++ interface.
After downloading, call:
>> run_example
in MATLAB to see an example implementation in action.
Look in run_example.m, example_mex.cpp (and optionally example_interface.m if you don't want to use the standard interface) to see how this is implemented, and copy the structure to interface with your own C++ classes.
This submission is inspired by the following newsgroup thread:
http://www.mathworks.com/matlabcentral/newsreader/view_thread/278243
Thanks to all those who have contributed.
Oliver Woodford (2019). Example MATLAB class wrapper for a C++ class (https://www.mathworks.com/matlabcentral/fileexchange/38964-example-matlab-class-wrapper-for-a-c-class), MATLAB Central File Exchange. Retrieved .
1.4.0.0 | Added a standard interface to avoid needing an interface class per mex wrapper. Also added an example script. |
|
1.3.0.0 | Add #includes suggested by Richard Crozier (thanks) to fix compilation in Linux. |
|
1.2.0.0 | 2nd attempt to fix compilation under linux. |
|
1.1.0.0 | Fix compile error in Linux - thanks to Andreas for highlighting the issue. |
Inspired: C++ MEX Development Utilities, Kinect 2 Interface for Matlab, FELICITY, MATLAB class wrapper for a C++ implementation of a Quadtree, Message Passing Algorithm for Decoding Binary LDPC Codes, crobarcro/mcode-cpp-utilities, Ray casting for deformable triangular 3D meshes
Create scripts with code, output, and formatted text in a single executable document.
Vojtech Vrba (view profile)
Brent Foster (view profile)
Marta Grobelna (view profile)
Chiheb Ben Hammouda (view profile)
A great code. However, when using it to wrap my C++ code I had an issue to work with types such as std::vector<double>!!! Do you have an idea what type can I define in mex so it can accept inputs or outputs defined as std::vector<double> in my C++ code? Many thanks.
Hannah Maria Baur (view profile)
Albert Piek (view profile)
Josh Sanz (view profile)
Oliver Woodford (view profile)
@robin loose: I'm not sure what you mean. Classes must be instantiated in order to use them. So this provides and interface to C++ class instances. That is what it is for. One class interface can be used to interface with all the instances of that class.
Robert (view profile)
I have a question: can I also use this to wrap an instance of the class? Say I create an instance of the class in C++ because of performance reasons and I want to wrap this to an instance of the class in MATLAB. Is such a thing possible? Thanks.
Mendi (view profile)
Jiayi (view profile)
This class interface works like a charm! However I found that if you create and delete one instance of class_interface, and when you create and delete for the second time, MATLAB has very high change to crash. I have no idea how to solve this problem. I have tried to compile with and without mexLock.
Kevin (view profile)
Raunak Borker (view profile)
Great work! Thanks a ton for these files :D
proud zhu (view profile)
Alla (view profile)
Yang YU (view profile)
Thank you for your code.
I am working on Background subtraction project, and this code saved my life!!!
Thomas Pfeil (view profile)
Manuel Marin (view profile)
Excellent contribution.
Thanks Olly.
David van der Lijn (view profile)
I have been using this code for a while now ~6mnths. So far so good.
However Today i found some strange behavior, for 1 of my codes:
During a clear (clear all) two instances of the were present, 1 I created and 1 that MATLAB created somewhere during my code. This additional object was created not calling the constructor and has an uninitialized handle, a crash occurs on isValid().
I can imaging 2 options to counter this:
1) Assure that the handle is initialized (i don't know how this would work).
2) Only call "SBTL_fluids_mex('delete', this.objectHandle);" when the constructor "this = SBTL_fluids(varargin)" was called for this object.
moran x (view profile)
Xavier (view profile)
Jozsef (view profile)
Eric Johnson (view profile)
This is a straightforward, great example for how create an interface between MATLAB and a C++ object.
Bryan Womack (view profile)
Great example.
David (view profile)
Looks intriguing, but I get the following error message when I try to compile: fatal error C1083: Cannot open include file: 'stdint.h': No such file or directory.
I read up online a bit and it's because my version of Visual Studio (2008) does not support this library. If Matlab uses visual studio to compile, you'll need to download these libraries to run and add an -i argument to tell the file location when compiling: https://code.google.com/p/msinttypes/downloads/detail?name=msinttypes-r26.zip
Hanse (view profile)
Oliver Woodford (view profile)
Joel: It would seem to be valid, but I cannot comment on whether it is safe. I would also imagine the pointer points to a static string, though. Try it.
Joel Andersson (view profile)
Is it safe to change the type of class_handle<base>::name_m to const char*? I imagine that "typeid(base).name()" returns a pointer to something with static storage.
Oliver Woodford (view profile)
An Tran Lam: The type cast is required because MATLAB arrays can only contain values, not pointers, and pointers can be up to 64 bits long (on current hardware).
An Tran Lam (view profile)
I know how to use the software, but don't understand why it works?
Can you explain why do you need to cast into <uint64_t> type?
*((uint64_t *)mxGetData(out)) = reinterpret_cast<uint64_t>(new class_handle<base>(ptr));
Kota Yamaguchi (view profile)
Hello, I made a development kit for this design pattern, if anyone interested. https://github.com/kyamagu/mexplus
Oliver Woodford (view profile)
Shawn: There's nothing special about that number. But, no, you don't need a different signature per class, as the code also records the name of the class (a second signature, if you like), and checks this against the expected name when casting back to a pointer. This means it would throw an error if you tried to cast a pointer of one class to a pointer of another.
Hanse (view profile)
Shawn Walker (view profile)
I have a question about class_handle.hpp:
Regarding this line:
#define CLASS_HANDLE_SIGNATURE 0xFF00F0A5
What is so special about that number? Could I make up anything, as long as it is consistent in the C++ code?
The reason I ask is if I have two separate C++ classes that are mex-ed and interfaced using your approach. It seems I should use a different signature for each C++ class, for safety's sake. Is this true?
Hanse (view profile)
Oliver Woodford (view profile)
Shawn: The code is as intended. I wrote it that way with the intention that people would change the lower bound on number of inputs to suit their needs. You could have an upper bound too, but it's not vital, whereas a lower bound is.
Shawn Walker (view profile)
This is a great submission.
However, one minor comment. This code is taken from your class_interface_mex.cpp file:
if (!strcmp("train", cmd)) {
// Check parameters
if (nlhs < 0 || nrhs < 2)
mexErrMsgTxt("Train: Unexpected arguments.");
// Call the method
dummy_instance->train();
return;
Shouldn't it be:
if (nlhs > 0 || nrhs > 2)
because your "train" method does not need any inputs or outputs?
Oliver Woodford (view profile)
Greg: Thanks for your input. Yes, the locking mechanism causes problems if you free an instance in a different mex file from that in which it was allocated. You can certainly remove the locking. However, as I stated in the associated newsgroup thread, I found that MATLAB crashes when I call "clear functions" if I don't use the file lock. As such, my advice is to keep the lock where possible, and design your software such that each instance is freed in the same mex file it is allocated in.
Greg (view profile)
Very useful code!
Found some interesting behavior though.
From my observations, as far as the operating system is concerned, all mex-files that you call from a single instance of MATLAB share the same memory segmentation. That is, you can create a C++ object in one mex-file, pass the handle to that object back into MATLAB, then delete the object in a different mex-file. This seems to work just fine and is handy in the case where the code of one class creates instances of another class.
This gets funky with the calls to mexLock() and mexUnlock() though. mexLock and mexUnlock are automatically keyed to the currently-running mex-file. So, if an object of Class_B is created inside Class_A_mex and convertPtr2Mat is called to pass that pointer back to MATLAB, you've just added an extra lock to Class_A_mex that won't be unlocked when Class_A is deleted. The Class_B_mex delete method seems to delete the Class_B object just fine, but it doesn't know anything about the mexLock on Class_A_mex.
For the moment, I've created a workaround by creating a "convertPtr2MatLockless" function in "class_handle.hpp" that's an exact copy of "convertPtr2Mat" except that it doesn't call mexLock(). I call the "Lockless" version whenever creating an object of a different class than the one the mex file is for.
I'm not all that happy with that workaround, but I don't really know how important the mexLock() is. At the very least, it doesn't appear to be necessary to keep the C++ delete methods from causing segfaults.
Greg (view profile)
Oliver Woodford (view profile)
Bin: Those members provide a means of checking that you are not casting a random memory address to a pointer to an instance of the base class. Doing that could lead to some bad things happening, so it is a protection against that.
Bin (view profile)
Can you explain to me what the reason for using class_handle with signature_m and name_m? What if we don't use those two members and just use the base class directly?
thank you very much.
Paul Dugas (view profile)
How about moving the SIGNATURE into the template parameters?
template<class base, uint32_t SIGNATURE> ...
This would allow it to be changed for different derivations.
$0.02
Ander Biguri (view profile)
Oliver Woodford (view profile)
Szigeti: your compile error is not related to this submission.
Fernando: the error you get seems self explanatory. You need to make sure class_handle.hpp, which comes with this submission, is in the same folder as the cpp file being compiled.
Szigeti (view profile)
Hello
I have run the example successfully, and even managed to make new functions, in my class, and gave a matrix as an out parameter. However I want to import my code into the given class, as a function. It opens a dll in C++ to a COM 2 device. I have overloaded some operator like [], =, *; I have read that matlab support overloading, but this is not matlab code. So I am confused a bit. In my opinion the vs 2010 compiler that I have mex -setup-ed, should work. But it gives me this error. class_interface_mex.obj : error LNK2019: unresolved external symbol "public: class std::vector<int,class std::allocator<int> > & __cdecl EEGContainer::operator[](int)" (??AEEGContainer@@QEAAAEAV?$vector@HV?$allocator@H@std@@@std@@H@Z) referenced in function "public: double * * __cdecl dummy::getEeg(void)" (?getEeg@dummy@@QEAAPEAPEANXZ)
class_interface_mex.obj : error LNK2019: unresolved external symbol "public: int __cdecl EEGContainer::getDataLenght(void)" (?getDataLenght@EEGContainer@@QEAAHXZ) referenced in function "public: double * * __cdecl dummy::getEeg(void)" (?getEeg@dummy@@QEAAPEAPEANXZ)
class_interface_mex.obj : error LNK2019: unresolved external symbol "public: __cdecl EEGContainer::~EEGContainer(void)" (??1EEGContainer@@QEAA@XZ) referenced in function "public: double * * __cdecl dummy::getEeg(void)" (?getEeg@dummy@@QEAAPEAPEANXZ)
class_interface_mex.obj : error LNK2019: unresolved external symbol "public: class EEGContainer & __cdecl EEGContainer::operator=(class EEGContainer const &)" (??4EEGContainer@@QEAAAEAV0@AEBV0@@Z) referenced in function "public: double * * __cdecl dummy::getEeg(void)" (?getEeg@dummy@@QEAAPEAPEANXZ)
class_interface_mex.obj : error LNK2019: unresolved external symbol "public: __cdecl EEGContainer::EEGContainer(int)" (??0EEGContainer@@QEAA@H@Z) referenced in function "public: double * * __cdecl dummy::getEeg(void)" (?getEeg@dummy@@QEAAPEAPEANXZ)
class_interface_mex.obj : error LNK2019: unresolved external symbol "public: __cdecl BMRecorder::BMRecorder(void)" (??0BMRecorder@@QEAA@XZ) referenced in function "public: double * * __cdecl dummy::getEeg(void)" (?getEeg@dummy@@QEAAPEAPEANXZ)
class_interface_mex.mexw64 : fatal error LNK1120: 6 unresolved externals
Fernando (view profile)
hello everyone, I am having trouble when mexing the class_interface_mex.cpp in matlab. The error that matlab gives me is the follwing:
>> mex class_interface_mex.cpp
class_interface_mex.cpp
\\aus.aero-ad.tamu.edu\UgradUsers$\f0p1107\Home\MATLAB\class_interface_mex.cpp(2) : fatal error C1083: Cannot open include file: 'class_handle.hpp': No such file or directory
C:\PROGRA~1\MATLAB\R2012A\BIN\MEX.PL: Error: Compile of '\\aus.aero-ad.tamu.edu\UgradUsers$\f0p1107\Home\MATLAB\class_interface_mex.cpp' failed.
Error using mex (line 206)
Unable to complete successfully.
Could anyone help me by letting me know how I can get rid of this error? I am no expert at coding so please try to keep your answer as simple as possible. Any help will be much appreciated.
Thank you!
Richard Crozier (view profile)
Hmmm, the FEX comment box gobbled my libraries, it's the following two that I needed
cstring
typeinfo
Richard Crozier (view profile)
I had to include both of the following to get it to compile on Linux
#include <cstring>
#include <typeinfo>
I'm using gcc 4.4.6. It ordered me to use typeinfo, I needed cstring to get strcmp.
Thanks for this though, it's incredibly useful to me!
Gabriele Gualandi (view profile)
Thank you Andreas for you suggestion about compiling in Unix!!!
Artem (view profile)
That's it, Oliver! Thanks a lot, a wonderful contribution!
Oliver Woodford (view profile)
Artem: If you want to put this in a class directory then the mex file needs to go in a subdirectory of that folder called private.
Artem (view profile)
Oliver, It is just 'mex class_interface_mex.cpp', right? It works fine if the mex-file is in a non-@ directory, but in the class dir it fails.
Oliver Woodford (view profile)
Artem: Did you mex the file, as explained in the file description?
Artem (view profile)
Great contribution!
I wonder if it is possible to put the class in @class_interface directory? In my case, Matlab cannot find class_interface_mex() function. Any suggestions?
Andreas (view profile)
code needs some tweaking to compile on non-windows systems. What's the reason for using 'raw_name()' instead of 'name()'. The former is MS specific.
--- orig/class_handle.hpp 2012-11-08 15:34:08.000000000 +0100
+++ new/class_handle.hpp 2012-11-27 16:46:50.831263148 +0100
@@ -4,12 +4,28 @@
#include <stdint.h>
#include <string>
+#if !(defined _WIN32 || defined _WIN64) // needed to compile on linux.
+ #include <string.h>
+ #include <typeinfo>
+ #define raw_name name // it would be better to change the code so that we use 'name()' instead of 'raw_name()'
+#endif
+
--- orig/class_interface_mex.cpp 2012-11-08 16:10:26.000000000 +0100
+++ new/class_interface_mex.cpp 2012-11-27 16:46:47.375263270 +0100
@@ -1,6 +1,10 @@
#include "mex.h"
#include "class_handle.hpp"
+#if !(defined _WIN32 || defined _WIN64) // needed to compile on linux.
+ #include <string.h>
+#endif
+
// The class that we are interfacing to
class dummy
{
Francesco Montorsi (view profile)
Works great! perfect to start interfacing C++ object-oriented code to MATLAB
Matthew (view profile)
Great submission developed from an informative newsgroup thread (referred to in description).