I'm trying to build a python interface to a C++ class I have, which unfortunately contains a mixture of both raw and shared pointer objects / return methods. Essentially, with this interface, I'm stuck with certain functions that return raw pointers due to design constraints (i.e., the data structure defines a descending hierarchy, i.e., A -> B -> C, with shared pointers moving down, and raw pointers pointing back up, in order to break cyclic ownership.)
The problem with this that I am observing however is that when I introduce a shared ptr template, i.e.:
%shared_ptr(fooType)
Then SWIG knows to wrap / create proxy classes for fooType
, but then not for fooType*
. (Conversely, if I don't include the %shared_ptr
macro, SWIG does create the proxy classes for the raw pointer.)
My problem comes into play as follows - I need to return a vector of raw pointer objects. So for example, here is my MWE:
fooType.h
#include <iostream>
#include <vector>
class fooType{
public:
fooType() { };
~fooType() { };
void printFoo() { std::cerr << "FOO!" << std::endl; }
static std::shared_ptr<fooType> make_shared() {
return std::shared_ptr<fooType>(new fooType());
}
static fooType* newPtr() { return new fooType(); }
static std::vector<fooType*> newVecPtr() {
std::vector<fooType*> retVec;
for( size_t i = 0; i < 3; ++i) { retVec.push_back(new fooType()); }
return retVec;
}
};
fooType.i
%module fooType
%include <std_map.i>
%include <std_shared_ptr.i>
%include <std_vector.i>
%{
#include "fooType.h"
%}
%shared_ptr(fooType);
%include "fooType.h"
%template(fooVec) std::vector<fooType>;
%template(fooPtrVec) std::vector<fooType*>;
testFooType.py
import fooType as fooMod
ft = fooMod.fooType.make_shared()
ftPtr = fooMod.fooType.newPtr()
fooVec = fooMod.fooType.newVecPtr()
print(ftPtr)
print(ft)
print(fooVec)
for foo in fooVec:
print(foo)
foo.printFoo()
This gives me:
<fooType.fooType; proxy of <Swig Object of type 'std::shared_ptr< fooType > *' at 0x7fd83ccfeb10> >
<fooType.fooType; proxy of <Swig Object of type 'std::shared_ptr< fooType > *' at 0x7fd83ccfec30> >
<fooType.fooPtrVec; proxy of <Swig Object of type 'std::vector< fooType * > *' at 0x7fd83ccfeba0> >
<Swig Object of type 'fooType *' at 0x7fd834c1dba0>
Traceback (most recent call last):
File "testFooType.py", line 13, in <module>
foo.printFoo()
AttributeError: 'SwigPyObject' object has no attribute 'printFoo'
If I comment out the %shared_ptr(fooType)
macro, I get:
<fooType.fooType; proxy of <Swig Object of type 'std::vector< fooType * >::value_type' at 0x7feab54b42a0> >
<fooType.fooTypePtr; proxy of <Swig Object of type 'std::shared_ptr< fooType > *' at 0x7feab54b4240> >
<fooType.fooPtrVec; proxy of <Swig Object of type 'std::vector< fooType * > *' at 0x7feab54b4210> >
<fooType.fooType; proxy of <Swig Object of type 'std::vector< fooType * >::value_type' at 0x7feab54b4780> >
FOO!
<fooType.fooType; proxy of <Swig Object of type 'std::vector< fooType * >::value_type' at 0x7feab54b4c90> >
FOO!
<fooType.fooType; proxy of <Swig Object of type 'std::vector< fooType * >::value_type' at 0x7feab54b4780> >
FOO!
So, what am I doing incorrectly here? In other words, how can I get SWIG to produce a proxy class for my raw pointers and my shared pointers simultaneously, especially when I'm wrapping them into a vector?
Note that I don't necessarily see a way to use something like std::enabled_shared_from_this
as illustrated here, namely because I'm stuck with the interface I have on the C++ side (i.e., I can't modify the class to add an inheritance from enable_shared_from_this
).
Mostly, I'd like to know why the proxy class generation gets clobbered when I enable shared pointers and how I might work around that. (I've tried developing my own typemap to parse out the pointers and put them back into a list, but this doesn't seem to help; I still end up with SWIG Objects, which I can't deference.)