Search code examples
c++pythonboostswigshared-ptr

SWIG, boost shared pointers and inheritance


I'm having trouble with SWIG, shared pointers, and inheritance.

I am creating various c++ classes which inherit from one another, using Boost shared pointers to refer to them, and then wrapping these shared pointers with SWIG to create the python classes.

My problem is the following:

  • B is a subclass of A
  • sA is a shared pointer to A
  • sB is a shared pointer to B
  • f(sA) is a function expecting a shared pointer to A

  • If I pass sB to f() then an error is raised.

  • This error only occurs at the python level.
  • At the C++ level I can pass sB to f() without a problem.

I have boost 1.40 and swig 1.3.40.

Below are the contents of 5 files which will reproduce the problem with:

python setup.py build_ext --inplace
python test.py

swig_shared_ptr.h

#ifndef INCLUDED_SWIG_SHARED_PTR_H
#define INCLUDED_SWIG_SHARED_PTR_H

#include <boost/shared_ptr.hpp>

class Base {};

class Derived : public Base {};

typedef boost::shared_ptr<Base> base_sptr;
typedef boost::shared_ptr<Derived> derived_sptr;

void do_something (base_sptr bs);

base_sptr make_base();
derived_sptr make_derived();

#endif

swig_shared_ptr.cc

#include <iostream>
#include "swig_shared_ptr.h"

void do_something (base_sptr bs)
{
  std::cout << "Doing something." << std::endl;
}

base_sptr make_base() { return base_sptr(new Base ()); };
derived_sptr make_derived() { return derived_sptr(new Derived ()); };

swig_shared_ptr.i

%module(docstring="
Example module showing problems I am having with SWIG, shared pointers
and inheritance.
") swig_shared_ptr

%{
#include "swig_shared_ptr.h"
%}

%include <swig_shared_ptr.h>
%include <boost_shared_ptr.i>
%template(base_sptr) boost::shared_ptr<Base>;
%template(derived_sptr) boost::shared_ptr<Derived>;

setup.py

"""
setup.py file for swig_shared_ptr
"""

from distutils.core import setup, Extension

swig_shared_ptr_module = Extension('_swig_shared_ptr',
                         include_dirs = ['/usr/include/boost'],
                         sources=['swig_shared_ptr.i', 'swig_shared_ptr.cc'],
                         )

setup (name = 'swig_shared_ptr',
       version = '0.1',
       author = "Ben",
       description = """Example showing problems I am having with SWIG, shared
                        pointers and inheritance.""",
       ext_modules = [swig_shared_ptr_module],
       py_modules = ["swig_shared_ptr"],
       )

test.py

import swig_shared_ptr as ssp

bs = ssp.make_base()
dr = ssp.make_derived()

# Works fine.
ssp.do_something(bs) 
# Fails with "TypeError: in method 'do_something', argument 1 of type 'base_sptr'"
ssp.do_something(dr) 

Solution

  • The following change appears to solve the problem.

    In swig_shared_ptr.i the two lines:

    %template(base_sptr) boost::shared_ptr<Base>;
    %template(derived_sptr) boost::shared_ptr<Derived>;
    

    are moved so that they are above the line

    %include <swig_shared_ptr.h>
    

    and are then replaced (in SWIG 1.3) by:

    SWIG_SHARED_PTR(Base, Base)
    SWIG_SHARED_PTR_DERIVED(Derived, Base, Derived)    
    

    or (in SWIG 2.0) by:

    %shared_ptr(Base)
    %shared_ptr(Derived)