从MATLAB中调用MEX中的C ++类方法

我有一个DLP工具包,我需要使用C ++ API通过MATLAB进行控制。

比如说,我在一个名为dlp_controller.cpp / .c的mex文件中使用C / C ++来实现{load_data, load_settings,display_data}函数/方法。

我知道我可以调用dlp_controller(); 用MATLAB。

有没有办法可以直接从MATLAB调用这个mex的方法?

说我的dlp_controller.cpp mex看起来像:

 class dlp{ ... } dlp::dlp{ ... } dlp::load_data{ ... } dlp::load_settings{ ... } dlp::display_data{ ... } void mexFunction(int nlhs, mxArray *[],int nrhs, const mxArray *prhs[]{ ... } 

我可以以某种方式从MATLAB调用像dlp_controller.load_data这样的方法吗? 注意:解决方法可以是将变量发送到dlp_controller并使用该函数和传递的数据在内部调用该函数。

AFAIK,没有直接的方法,因为mexFunction接口相当平坦 。 但是,我可以想到一些不同的解决方法,可以让你接近。 根据您的需求选择最佳的一个。

  1. 最简单的方法是在mex函数中创建dlp类的全局实例。 使mex函数的第一个参数调用一个字符串,该字符串指示调用全局对象的哪个成员函数。 明显的缺点是你已经将你的mexfunction变成了单身。

  2. 如果您需要多个dlp实例,可以在mex函数中创建一些全局容器,例如std::map ,然后在MATLAB中通过某个名称引用每个dlp实例。 例如,要创建一个新实例,您可以使用map尚不存在的名称调用mex函数。 然后,您可以使用此名称调用mex函数,该字符串指示要调用的成员函数以及要传递给成员函数的任何参数。 还设置了一些约定,您可以通过该约定从map删除dlp实例。

  3. 与第二个解决方案类似,您可以将句柄返回给每个实例,而不是命名dlp实例。 例如,创建一个全局std::set ,当你有mex函数创建一个新的dlp实例时,将它添加到set并将指向分配对象的指针的副本返回给MATLAB(将其粘贴到一个mxUINT64_CLASS类型的标量变量。 对该对象调用成员函数的后续调用将把这个句柄变量传递给MATLAB中的mex函数,你将在mex文件中适当地转换它,在set找到它并调用成员函数。

这些方法都不是特别漂亮,但这些是我所知道的从mex文件中调用C ++类的成员函数的唯一方法。

您可能想看一下这个提交到MATLAB Central的内容。 据我所知,它展示了最佳实践,由包括MathWorkers在内的许多人提供新闻组建议。

http://www.mathworks.co.uk/matlabcentral/fileexchange/38964-example-matlab-class-wrapper-for-a-c++-class

最简单的方法是设计一个MEX包装器,它保存类对象的实例,并调度对该MEX二进制文件的调用。 我为那些试图用C ++开发MEX包装器的人创建了一个库。

https://github.com/kyamagu/mexplus

这是一个快速片段。

 // C++ class to be wrapped. class Database; // Instance session storage. template class mexplus::Session; // Constructor. MEX_DEFINE(new) (int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { InputArguments input(nrhs, prhs, 1); OutputArguments output(nlhs, plhs, 1); output.set(0, Session::create( new Database(input.get(0)))); } // Destructor. MEX_DEFINE(delete) (int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { InputArguments input(nrhs, prhs, 1); OutputArguments output(nlhs, plhs, 0); Session::destroy(input.get(0)); } // Member method. MEX_DEFINE(query) (int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { InputArguments input(nrhs, prhs, 2); OutputArguments output(nlhs, plhs, 1); const Database& database = Session::getConst(input.get(0)); output.set(0, database.query(input.get(1))); } // And so on... MEX_DISPATCH 

对于它的价值,这是我对这个问题的看法。 请参阅此GitHub存储库中的示例MEX文件和类包装器。 这是我不久前提出的一个解决方案,我刚刚在制作相关问题的答案时发现了这个问题 。 希望这对某人有所帮助。

设计目标

  • 管理C ++类的多个持久化实例
  • MATLAB中使用的小连续整数句柄(不是指针)
  • 透明地处理资源管理(即MATLAB从不负责为C ++类分配的内存):
    1. 如果MATLAB无法发出“删除”操作,则不会泄漏内存。
    2. 如果MEX文件过早卸载,则自动释放。
  • 防止过早的模块卸载
  • 在不检查幻数的情况下隐式validation句柄的有效性
  • 没有包装类或模仿mexFunction的函数,只是mexFunction中的直观switch-case块。

请注意,这些目标应该不考虑任何MATLAB类,但也可以帮助解决内存管理问题。 因此,生成的MEX文件可以安全地直接使用(但不是太优雅)。

实施概述

对于C ++类class_typemexFunction使用静态数据存储来保存整数句柄的持久性(在调用mexFunction之间)和动态分配的类实例的智能指针。 std::map用于此目的,这有助于定位已知句柄,只保证您的类的有效实例存在:

 typedef unsigned int handle_type; std::map> 

当(1)通过“删除”操作擦除表元素或(2)卸载MEX文件时, std::shared_ptr负责解除分配。

为了防止在MATLAB类实例存在时卸载MEX文件,每次创建新的C ++类实例时都会调用mexLock ,这会增加MEX文件的锁定计数。 每次删除C ++实例时mexUnlock调用mexUnlock ,从锁定计数中删除一个锁。

使用

  1. [In .cpp]在Actions枚举中枚举不同的动作(例如New,Delete,Insert等)。 对于每个枚举操作,指定一个字符串(例如“new”,“delete”,“insert”等)作为MATLAB中MEX函数的第一个参数传递。
  2. [In .cpp]自定义mexFunction主体中switch语句中每个动作的处理(例如,调用相关的C ++类方法)。
  3. [In .m](可选)创建一个派生自cppclass的类,为类所需的操作创建简单方法。

要求

具有以下C ++ 11function的现代编译器:

  • shared_ptr
  • auto
  • enum class
  • initializer_list (用于const map初始化)

Visual Studio 2013,最近的GCC(可能是-std=c++11 )和Clang从3.1开始。

资源

  • C ++组件(class_wrapper_template.cpp) ( mexFunction和实例映射)。 为要管理的C ++重命名和编辑它。
  • 基类(cppclass.m),用于通过MEX文件管理单个实例

替代设计,这里的用例更清晰,是使用init,fcnA,fcnB,fcnC,…方法等来定义单例类,使用相应的轻量级包装器…然后从MEX调用包装器。

例如

 class A { public: A getInstance() { if ( !instance ) instance = new A(...); return instance; } void fcnA(T1 a1, T2 a2) { //yada yada } private: static A* instance; }; A::instance = NULL; //begin wrappers for marshalling to class method A* getInstance( ) { return A::getInstance(); } void fcnA(T1 a1, T2 a2) { getInstance()->fcnA(a1,a2); } //ad nauseum