Memory leak fixed within wrap. Must call 'clear' before 'clear all' and 'clear classes'. Wrap now creates delete_classname files for all wrapped classes. MATLAB classes now derive from the handle superclass.
parent
cdbeebaf1d
commit
a1da906d33
|
@ -35,16 +35,22 @@ void Class::matlab_proxy(const string& classFile) const {
|
|||
string matlabName = qualifiedName();
|
||||
|
||||
// emit class proxy code
|
||||
file.oss << "classdef " << matlabName << endl;
|
||||
// we want our class to inherit the handle class for memory purposes
|
||||
file.oss << "classdef " << matlabName << " < handle" << endl;
|
||||
file.oss << " properties" << endl;
|
||||
file.oss << " self = 0" << endl;
|
||||
file.oss << " end" << endl;
|
||||
file.oss << " methods" << endl;
|
||||
// constructor
|
||||
file.oss << " function obj = " << matlabName << "(varargin)" << endl;
|
||||
BOOST_FOREACH(Constructor c, constructors)
|
||||
c.matlab_proxy_fragment(file,matlabName);
|
||||
file.oss << " if nargin ~= 13 && obj.self == 0, error('" << matlabName << " constructor failed'); end" << endl;
|
||||
file.oss << " end" << endl;
|
||||
// deconstructor
|
||||
file.oss << " function delete(obj)" << endl;
|
||||
file.oss << " delete_" << matlabName << "(obj);" << endl;
|
||||
file.oss << " end" << endl;
|
||||
file.oss << " function display(obj), obj.print(''); end" << endl;
|
||||
file.oss << " function disp(obj), obj.display; end" << endl;
|
||||
file.oss << " end" << endl;
|
||||
|
@ -62,6 +68,11 @@ void Class::matlab_constructors(const string& toolboxPath, const vector<string>&
|
|||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void Class::matlab_deconstructor(const string& toolboxPath, const vector<string>& using_namespaces) const {
|
||||
d.matlab_mfile (toolboxPath, qualifiedName());
|
||||
d.matlab_wrapper(toolboxPath, qualifiedName("::"), qualifiedName(), using_namespaces, includes);
|
||||
}
|
||||
/* ************************************************************************* */
|
||||
void Class::matlab_methods(const string& classPath, const vector<string>& using_namespaces) const {
|
||||
string matlabName = qualifiedName(), cppName = qualifiedName("::");
|
||||
|
@ -88,6 +99,7 @@ void Class::matlab_make_fragment(FileWriter& file,
|
|||
string matlabClassName = qualifiedName();
|
||||
BOOST_FOREACH(Constructor c, constructors)
|
||||
file.oss << mex << c.matlab_wrapper_name(matlabClassName) << ".cpp" << endl;
|
||||
file.oss << mex << d.matlab_wrapper_name(matlabClassName) << ".cpp" << endl;
|
||||
BOOST_FOREACH(StaticMethod sm, static_methods)
|
||||
file.oss << mex << matlabClassName + "_" + sm.name << ".cpp" << endl;
|
||||
file.oss << endl << "cd @" << matlabClassName << endl;
|
||||
|
@ -119,6 +131,7 @@ void Class::makefile_fragment(FileWriter& file) const {
|
|||
string file_base = c.matlab_wrapper_name(matlabName);
|
||||
file_names.push_back(file_base);
|
||||
}
|
||||
file_names.push_back(d.matlab_wrapper_name(matlabName));
|
||||
BOOST_FOREACH(StaticMethod c, static_methods) {
|
||||
string file_base = matlabName + "_" + c.name;
|
||||
file_names.push_back(file_base);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <string>
|
||||
|
||||
#include "Constructor.h"
|
||||
#include "Deconstructor.h"
|
||||
#include "Method.h"
|
||||
#include "StaticMethod.h"
|
||||
|
||||
|
@ -37,12 +38,15 @@ struct Class {
|
|||
std::vector<StaticMethod> static_methods; ///< Static methods
|
||||
std::vector<std::string> namespaces; ///< Stack of namespaces
|
||||
std::vector<std::string> includes; ///< header include overrides
|
||||
Deconstructor d;
|
||||
bool verbose_; ///< verbose flag
|
||||
|
||||
// And finally MATLAB code is emitted, methods below called by Module::matlab_code
|
||||
void matlab_proxy(const std::string& classFile) const; ///< emit proxy class
|
||||
void matlab_constructors(const std::string& toolboxPath,
|
||||
const std::vector<std::string>& using_namespaces) const; ///< emit constructor wrappers
|
||||
void matlab_deconstructor(const std::string& toolboxPath,
|
||||
const std::vector<std::string>& using_namespaces) const;
|
||||
void matlab_methods(const std::string& classPath,
|
||||
const std::vector<std::string>& using_namespaces) const; ///< emit method wrappers
|
||||
void matlab_static_methods(const std::string& classPath,
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* GTSAM Copyright 2010, Georgia Tech Research Corporation,
|
||||
* Atlanta, Georgia 30332-0415
|
||||
* All Rights Reserved
|
||||
* Authors: Frank Dellaert, et al. (see THANKS for the full author list)
|
||||
|
||||
* See LICENSE for the license information
|
||||
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @file Deconstructor.ccp
|
||||
* @author Frank Dellaert
|
||||
* @author Andrew Melim
|
||||
**/
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include "utilities.h"
|
||||
#include "Deconstructor.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace wrap;
|
||||
|
||||
/* ************************************************************************* */
|
||||
string Deconstructor::matlab_wrapper_name(const string& className) const {
|
||||
string str = "delete_" + className;
|
||||
return str;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void Deconstructor::matlab_mfile(const string& toolboxPath, const string& qualifiedMatlabName) const {
|
||||
|
||||
string matlabName = matlab_wrapper_name(qualifiedMatlabName);
|
||||
|
||||
// open destination m-file
|
||||
string wrapperFile = toolboxPath + "/" + matlabName + ".m";
|
||||
FileWriter file(wrapperFile, verbose_, "%");
|
||||
|
||||
// generate code
|
||||
file.oss << "function result = " << matlabName << "(obj";
|
||||
if (args.size()) file.oss << "," << args.names();
|
||||
file.oss << ")" << endl;
|
||||
file.oss << " error('need to compile " << matlabName << ".cpp');" << endl;
|
||||
file.oss << "end" << endl;
|
||||
|
||||
// close file
|
||||
file.emit(true);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
void Deconstructor::matlab_wrapper(const string& toolboxPath,
|
||||
const string& cppClassName,
|
||||
const string& matlabClassName,
|
||||
const vector<string>& using_namespaces, const vector<string>& includes) const {
|
||||
string matlabName = matlab_wrapper_name(matlabClassName);
|
||||
|
||||
// open destination wrapperFile
|
||||
string wrapperFile = toolboxPath + "/" + matlabName + ".cpp";
|
||||
FileWriter file(wrapperFile, verbose_, "//");
|
||||
|
||||
// generate code
|
||||
//
|
||||
generateIncludes(file, name, includes);
|
||||
cout << "Generate includes " << name << endl;
|
||||
generateUsingNamespace(file, using_namespaces);
|
||||
|
||||
file.oss << "void mexFunction(int nargout, mxArray *out[], int nargin, const mxArray *in[])" << endl;
|
||||
file.oss << "{" << endl;
|
||||
//Deconstructor takes 1 arg, the mxArray obj
|
||||
file.oss << " checkArguments(\"" << matlabName << "\",nargout,nargin," << "1" << ");" << endl;
|
||||
file.oss << " delete_shared_ptr< " << cppClassName << " >(in[0],\"" << matlabClassName << "\");" << endl;
|
||||
file.oss << "}" << endl;
|
||||
|
||||
// close file
|
||||
file.emit(true);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
|
@ -0,0 +1,61 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
|
||||
* GTSAM Copyright 2010, Georgia Tech Research Corporation,
|
||||
* Atlanta, Georgia 30332-0415
|
||||
* All Rights Reserved
|
||||
* Authors: Frank Dellaert, et al. (see THANKS for the full author list)
|
||||
|
||||
* See LICENSE for the license information
|
||||
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @file Deconstructor.h
|
||||
* @brief class describing a constructor + code generation
|
||||
* @author Frank Dellaert
|
||||
* @author Andrew Melim
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Argument.h"
|
||||
|
||||
namespace wrap {
|
||||
|
||||
// Deconstructor class
|
||||
struct Deconstructor {
|
||||
|
||||
/// Deconstructor creates an empty class
|
||||
Deconstructor(bool verbose = true) :
|
||||
verbose_(verbose) {
|
||||
}
|
||||
|
||||
// Then the instance variables are set directly by the Module deconstructor
|
||||
ArgumentList args;
|
||||
std::string name;
|
||||
bool verbose_;
|
||||
|
||||
// MATLAB code generation
|
||||
// toolboxPath is main toolbox directory, e.g., ../matlab
|
||||
// classFile is class proxy file, e.g., ../matlab/@Point2/Point2.m
|
||||
|
||||
/// wrapper name
|
||||
std::string matlab_wrapper_name(const std::string& className) const;
|
||||
|
||||
/// m-file
|
||||
void matlab_mfile(const std::string& toolboxPath,
|
||||
const std::string& qualifiedMatlabName) const;
|
||||
|
||||
/// cpp wrapper
|
||||
void matlab_wrapper(const std::string& toolboxPath,
|
||||
const std::string& cppClassName,
|
||||
const std::string& matlabClassName,
|
||||
const std::vector<std::string>& using_namespaces,
|
||||
const std::vector<std::string>& includes) const;
|
||||
};
|
||||
|
||||
} // \namespace wrap
|
||||
|
|
@ -12,6 +12,8 @@
|
|||
/**
|
||||
* @file Module.ccp
|
||||
* @author Frank Dellaert
|
||||
* @author Alex Cunningham
|
||||
* @author Andrew Melim
|
||||
**/
|
||||
|
||||
#include "Module.h"
|
||||
|
@ -49,6 +51,7 @@ Module::Module(const string& interfacePath,
|
|||
Argument arg0, arg;
|
||||
ArgumentList args0, args;
|
||||
Constructor constructor0(enable_verbose), constructor(enable_verbose);
|
||||
Deconstructor deconstructor0(enable_verbose), deconstructor(enable_verbose);
|
||||
Method method0(enable_verbose), method(enable_verbose);
|
||||
StaticMethod static_method0(enable_verbose), static_method(enable_verbose);
|
||||
Class cls0(enable_verbose),cls(enable_verbose);
|
||||
|
@ -180,7 +183,10 @@ Module::Module(const string& interfacePath,
|
|||
>> str_p("};"))
|
||||
[assign_a(cls.namespaces, namespaces)]
|
||||
[append_a(cls.includes, namespace_includes)]
|
||||
[assign_a(deconstructor.name,cls.name)]
|
||||
[assign_a(cls.d, deconstructor)]
|
||||
[push_back_a(classes,cls)]
|
||||
[assign_a(deconstructor,deconstructor0)]
|
||||
[assign_a(cls,cls0)];
|
||||
|
||||
Rule namespace_def_p =
|
||||
|
@ -339,6 +345,9 @@ void Module::matlab_code(const string& toolboxPath,
|
|||
cls.matlab_static_methods(toolboxPath,using_namespaces);
|
||||
cls.matlab_methods(classPath,using_namespaces);
|
||||
|
||||
// create deconstructor
|
||||
cls.matlab_deconstructor(toolboxPath,using_namespaces);
|
||||
|
||||
// add lines to make m-file
|
||||
makeModuleMfile.oss << "%% " << cls.qualifiedName() << endl;
|
||||
makeModuleMfile.oss << "cd(toolboxpath)" << endl;
|
||||
|
|
|
@ -281,8 +281,6 @@ gtsam::Matrix unwrap< gtsam::Matrix >(const mxArray* array) {
|
|||
// inspired by mexhandle, but using shared_ptr
|
||||
//*****************************************************************************
|
||||
|
||||
template<typename T> class Collector;
|
||||
|
||||
template<typename T>
|
||||
class ObjectHandle {
|
||||
private:
|
||||
|
@ -296,13 +294,13 @@ public:
|
|||
ObjectHandle(T* ptr) :
|
||||
type(&typeid(T)), t(shared_ptr<T> (ptr)) {
|
||||
signature = this;
|
||||
Collector<T>::register_handle(this);
|
||||
this->print("Constructor");
|
||||
}
|
||||
|
||||
// Constructor for shared pointers
|
||||
// Creates shared pointer, will delete if is last one to hold pointer
|
||||
ObjectHandle(shared_ptr<T> ptr) :
|
||||
type(&typeid(T)), t(ptr) {
|
||||
/*type(&typeid(T)),*/ t(ptr) {
|
||||
signature = this;
|
||||
}
|
||||
|
||||
|
@ -364,42 +362,6 @@ public:
|
|||
return obj;
|
||||
}
|
||||
|
||||
friend class Collector<T> ; // allow Collector access to signature
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// ------------------ Garbage Collection -------------------
|
||||
// ---------------------------------------------------------
|
||||
|
||||
// Garbage collection singleton (one collector object for each type T).
|
||||
// Ensures that registered handles are deleted when the dll is released (they
|
||||
// may also be deleted previously without problem).
|
||||
// The Collector provides protection against resource leaks in the case
|
||||
// where 'clear all' is called in MatLab. (This is because MatLab will call
|
||||
// the destructors of statically allocated objects but not free-store allocated
|
||||
// objects.)
|
||||
template <typename T>
|
||||
class Collector {
|
||||
typedef ObjectHandle<T> Handle;
|
||||
typedef std::list< Handle* > ObjList;
|
||||
typedef typename ObjList::iterator iterator;
|
||||
ObjList objlist;
|
||||
public:
|
||||
~Collector() {
|
||||
for (iterator i= objlist.begin(); i!=objlist.end(); ++i) {
|
||||
if ((*i)->signature == *i) // check for valid signature
|
||||
delete *i;
|
||||
}
|
||||
}
|
||||
|
||||
static void register_handle (Handle* obj) {
|
||||
static Collector singleton;
|
||||
singleton.objlist.push_back(obj);
|
||||
}
|
||||
|
||||
private: // prevent construction
|
||||
Collector() {}
|
||||
Collector(const Collector&);
|
||||
};
|
||||
|
||||
//*****************************************************************************
|
||||
|
@ -462,6 +424,7 @@ mxArray* wrap_shared_ptr(shared_ptr< Class > shared_ptr, const char *classname)
|
|||
*/
|
||||
template <typename Class>
|
||||
shared_ptr<Class> unwrap_shared_ptr(const mxArray* obj, const string& className) {
|
||||
//Why is this here?
|
||||
#ifndef UNSAFE_WRAP
|
||||
bool isClass = mxIsClass(obj, className.c_str());
|
||||
if (!isClass) {
|
||||
|
@ -475,4 +438,20 @@ shared_ptr<Class> unwrap_shared_ptr(const mxArray* obj, const string& className)
|
|||
return handle->get_object();
|
||||
}
|
||||
|
||||
template <typename Class>
|
||||
void delete_shared_ptr(const mxArray* obj, const string& className) {
|
||||
//Why is this here?
|
||||
#ifndef UNSAFE_WRAP
|
||||
bool isClass = true;//mxIsClass(obj, className.c_str());
|
||||
if (!isClass) {
|
||||
mexPrintf("Expected %s, got %s\n", className.c_str(), mxGetClassName(obj));
|
||||
error("Argument has wrong type.");
|
||||
}
|
||||
#endif
|
||||
mxArray* mxh = mxGetProperty(obj,0,"self");
|
||||
if (mxh==NULL) error("unwrap_reference: invalid wrap object");
|
||||
ObjectHandle<Class>* handle = ObjectHandle<Class>::from_mex_handle(mxh);
|
||||
delete handle;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
%MATLAB testing file for memory allocation and leaks
|
||||
%Andrew Melim
|
||||
|
||||
addpath([pwd,'/../../../toolbox/gtsam']);
|
||||
for i=1:10
|
||||
p = gtsamPoint2()
|
||||
end
|
Loading…
Reference in New Issue