2

I have some C++ code that returns a boost::shared_ptr to a std::vector, however I am unable to get SWIG to wrap this correctly to make the object iterable in Python. Without the boost::shared_ptr it works fine. Does anyone know how to wrap a vector when it's inside a shared_ptr?

Here is an example demonstrating the problem:

%module example

%include <std_vector.i>
%include <boost_shared_ptr.i>

%shared_ptr(Inner)
%shared_ptr(InnerVector)

%inline %{
#include <boost/shared_ptr.hpp>
#include <vector>

struct Inner {
  int dummy;
};
typedef std::vector< boost::shared_ptr<Inner> > InnerVector;
typedef boost::shared_ptr<InnerVector> InnerVectorPtr;

InnerVectorPtr getVectorPtr()
{
  InnerVectorPtr v(new InnerVector());
  boost::shared_ptr<Inner> i(new Inner);
  i->dummy = 222;
  v->push_back(i);
  return v;
}

%}

%template(InnerVector) ::std::vector< boost::shared_ptr<Inner> >;

And an example Python script:

import example

v = example.getVectorPtr()
print 'Vector is:', v
for i in v:
     print 'Instance is:', i
     print 'Value is:', i.dummy

Which for me, says this:

Vector is: <Swig Object of type 'InnerVectorPtr *' at 0x1127270>
Traceback (most recent call last):
  File "test.py", line 5, in <module>
    for i in v:
TypeError: 'SwigPyObject' object is not iterable

Any suggestions?

Malvineous
  • 25,144
  • 16
  • 116
  • 151
  • Why are you returning a shared pointer to vector? – Joseph Lisee Apr 30 '11 at 07:48
  • Because the vector can have a large number of entries and I want to avoid it being copied on return, as the function will be called frequently. I could return a reference to the vector instead (although SWIG doesn't like that) but it would mean the caller has to be more careful. But if you have any better suggestions I'm all ears. – Malvineous Apr 30 '11 at 11:49
  • If you haven't done the profiling to show that copying that vector is an issue, I wouldn't worry about it and copy it around all you want. – Joseph Lisee May 03 '11 at 08:52
  • That's a fair point, but I'm pretty sure profiling won't bring any surprises here - the vector contains around 1000 items to be drawn on the screen many times per second, so if I removed the shared pointer I would no doubt have to refactor the code to cache the vector anyway, lest the framerate suffer... EDIT: Also, I resent having to change my fine C++ code just because the Python wrapper isn't up to scratch ;-) – Malvineous May 03 '11 at 09:07

2 Answers2

1

You might want to try Boost.Python and Py++. If you already using Boost it provides a very nice wrapping (and pretty much automatic wrapping) of complex C++ constructs. I have used it in several projects.

Also you should take a look at this question it looks related but not exactly your issue.

Community
  • 1
  • 1
Joseph Lisee
  • 3,439
  • 26
  • 21
  • Thanks for the pointer - yes I had seen that question but I do have that part working - it's only when adding another layer of shared pointers it fails. I originally steered away from Boost.Python as it looked like I had to master bjam to get it to work. Do you know whether it's possible to use bjam to cross-compile the bindings on a Linux machine to run on a Python interpreter under Windows? – Malvineous Apr 30 '11 at 11:45
  • You certainly don't have to use bjam to use Boost.Python. There is no magic here at all, you just need to supply the linker/compiler the right flags so they can find the correct versions of Boost.Python and libPython (correct being the versions you built Boost.Python against). I assume if you had a properly C++ & C cross compilation system setup for windows, you should be able to able make wrappers as well. You would just need a version of Boost.Python and libPython compiled for windows. – Joseph Lisee May 01 '11 at 05:28
1

Did you solve your problem?

I was thinking that it might be a problem with name manging, since you use the same name InnerVector twice:

%template(InnerVector) ::std::vector< boost::shared_ptr<Inner> >;

typedef std::vector< boost::shared_ptr<Inner> > InnerVector;

The error TypeError: 'SwigPyObject' object is not iterable usually means that SWIG does not understand that the object is e.g. a vector and should be converted into a Python list.

RobW
  • 309
  • 1
  • 4
  • 12
  • 1
    Unfortunately I gave up and just removed the Python interface to my code. Does your suggestion work in my example code above? I have since reinstalled and don't have SWIG any more to test! – Malvineous Feb 29 '12 at 23:18
  • I have tried to run the above example, and get the same problem. Apparently, SWIG can handle the name mangling problems. However, you cannot use a 'shared_ptr' directly in Python. You might want to have a look on [this thread](http://stackoverflow.com/questions/5265637/swig-wrapped-vector-of-vectors-c-to-python-how-to-recognise-the-inner-vect) for wrapping of vectors in general. I have used boost::shared_ptr<> objects in Python, but only as a bridging data container between different SWIG-wrapped C++ functions. – RobW Mar 06 '12 at 14:05