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

Popular posts from this blog

python - Selenium remoteWebDriver (& SauceLabs) Firefox moseMoveTo action exception -

html - How to custom Bootstrap grid height? -

transpose - Maple isnt executing function but prints function term -