Initialize a reference to a C# shared pointer from C++ using SWIG -
i’m trying initialize, in c++, reference boost shared pointer passed c#, while trying maintain inheritance tree. want able create variable in c# pass dll instantiate internally (so can manage memory allocation in same context).
here’s c++ test case (in file swigtest.h) :
#include <string> #include <boost/shared_ptr.hpp> template<class t> using sref = boost::shared_ptr<t>; class factoryclass { public: factoryclass() {} ~factoryclass() {} //normally use return value, swig uses polymorphism simulate templates //and polymorphism on return type not supported c#. (i identifier 'getreference' redefined error on swigtest.i compilation). //so thought i’d pass sref& parameter instead of having no parameters @ all. template <class t> static sref<t> getreference( sref<t>& inout ) { inout = sref<t>( new t(1) ); return inout; } void testing( int& toto ) {}; }; class baseclass { public: baseclass() { m_flag = -1; }; baseclass(int i) { m_flag = i; }; virtual ~baseclass() {}; virtual std::string getname() = 0; int m_flag; }; class firstclass : public baseclass { public: firstclass() {}; firstclass(int i) : baseclass( ) {}; virtual ~firstclass() {}; virtual std::string getname() { return "first class"; }; }; class secondclass : public baseclass { public: secondclass() {}; secondclass(int i) : baseclass( ) {}; virtual ~secondclass() {}; virtual std::string getname() { return "second class"; }; }; here’s current swig interface file :
%module swigtest %include "std_string.i" %include "boost_shared_ptr.i" %{ #include "../include/swigtest.h" %} %shared_ptr( baseclass ); %shared_ptr( firstclass ); %shared_ptr( secondclass ); %include "../include/swigtest.h" %template(boostbaseptr) boost::shared_ptr<baseclass>; %template(sharedbase) sref<baseclass>; %template(boostfirstptr) boost::shared_ptr<firstclass>; %template(sharedfirst)sref<firstclass>; %template(getreference)factoryclass::getreference<firstclass>; %template(boostsecondptr) boost::shared_ptr<secondclass>; %template(sharedsecond)sref<secondclass>; %template(getreference)factoryclass::getreference<secondclass>; and here’s works , doesn’t in c# :
public class swiginterface { private firstclass m_first; private secondclass m_second = new secondclass(-2); void testswig () { m_first = factoryclass.getreference( m_first ); //the returned reference copied c++ factoryclass.getreference( m_second ); //m_second never changed firstclass anotherfirst = new firstclass(-1) ; baseclass bc = factoryclass.getreference( anotherfirst); //bc equal new instance of firstclass anotherfirst not correctly replaced //this case ideally want use secondclass nothing ; factoryclass.getreference( nothing ) ; //nullreferenceexception (because swig generated interface uses nothing.cptr() pass pointer refs). } } i tried lot of %typename gymnastics replace signature of factoryclass.getreference( firstclass ) factoryclass.getreference( out firstclass ) (or ref firstclass) can’t find way properly.
in perfect world, generate void getreference<t>( ref t inout ) in factoryclass in c#, adding method using swig %extend keyword doesn't generate because have instantiate every template need.
if understand point, have reached swig limit. have faced same issue. each pointer (smart or not) loses polymorphism once in c#.
you need provide special factory baseclass in c# side, using %pragma(csharp) directive. need map pointer csout typemap this:
%typemap(csout, excode=swigexcode) baseclass*, std::shared_ptr<baseclass>, std::shared_ptr<baseclass> & { system.intptr cptr = $imcall; // following line call special factory baseclass ret = $imclassname.createbaseclass(cptr, $owner);$excode return ret; } your factory this:
%pragma(csharp) imclasscode=%{ public static baseclass createbaseclass(system.intptr cptr, bool owner) { baseclass ret = null; if (cptr == system.intptr.zero) { return ret; } string name = ($imclassname.baseclass_getname(new system.runtime.interopservices.handleref(null, cptr))); switch (name) { case "first class": return new firstclass(cptr, owner); case "second class": return new secondclass(cptr, owner); default: return null; } } %} i didn't test it, maybe there things change or adapt. should work.
Comments
Post a Comment