File Exchange

image thumbnail

Example MATLAB class wrapper for a C++ class

version 1.4.0.0 (8.28 KB) by Oliver Woodford
An example of how to safely encapsulate a C++ class in a MATLAB class, via a mex interface.

43 Downloads

Updated 08 Feb 2018

View License

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.

Comments and Ratings (58)

Brent Foster

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.

Albert Piek

Josh Sanz

@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

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

Jiayi

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

Great work! Thanks a ton for these files :D

proud zhu

Alla

Yang YU

Thank you for your code.
I am working on Background subtraction project, and this code saved my life!!!

Manuel Marin

Excellent contribution.
Thanks Olly.

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

Xavier

Jozsef

Eric Johnson

This is a straightforward, great example for how create an interface between MATLAB and a C++ object.

Great example.

David

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

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.

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.

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

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

Hello, I made a development kit for this design pattern, if anyone interested. https://github.com/kyamagu/mexplus

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

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

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.

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?

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

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

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

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

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

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

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

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!

Hmmm, the FEX comment box gobbled my libraries, it's the following two that I needed

cstring
typeinfo

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!

Thank you Andreas for you suggestion about compiling in Unix!!!

Artem

That's it, Oliver! Thanks a lot, a wonderful contribution!

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

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.

Artem: Did you mex the file, as explained in the file description?

Artem

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

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
{

Works great! perfect to start interfacing C++ object-oriented code to MATLAB

Matthew

Great submission developed from an informative newsgroup thread (referred to in description).

Updates

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.

MATLAB Release Compatibility
Created with R2012b
Compatible with any release
Platform Compatibility
Windows macOS Linux