[C++-sig] const shared_ptr and py++ / boost.python

Nicolas Regnault nicolas.regnault at lpnhe.in2p3.fr
Thu Jun 4 22:37:59 CEST 2009


Dear all:

I am wrapping a library which relies heavily on boost smart pointers 
(mainly boost::shared_ptr< T >). In particular, many functions and methods 
have signatures like:

    void my_func( const boost::shared_ptr< MyClass > & );

Everything works well from within C++ programs. But I encounter a serious 
problem with the wrappers I have generated with py++. Indeed, when passing 
from python, something which wraps a "shared_ptr< MyClass >" to 
my_function(), the code within the function apparently gets a shared_ptr 
with a use_count equal to 1 (pointing to the same address), whatever the 
use_count of the shared_ptr passed to the function.

I haven't been able to see what boost.python is doing in between, but 
something gets altered. Any idea of what is wrong with the wrappers ?


Here is a small example:

////////////////////////////////////////////////////////////////////////
// -*- C++ -*- //
//tst.hpp
//

#ifndef TST_HPP
#define TST_HPP

#include <vector>
#include <boost/shared_ptr.hpp>


struct Foo
{
   Foo() : count(0) {}
   int count;
};

typedef std::vector< boost::shared_ptr< Foo > > FooVector;

void build_vector( boost::shared_ptr< Foo > &, FooVector & );

// print the shared_ptr<>::use_count
void print_use_count( boost::shared_ptr< Foo > & );

// print the shared_ptr<>::use_count
void print_use_count_const( const boost::shared_ptr< Foo > & );


#endif

////////////////////////////////////////////////////////////////////////
// -*- C++ -*-
//
// tst.cpp
//

#include <iostream>
#include <iomanip>
#include "tst.hpp"


using namespace std;
using namespace boost;


void build_vector( shared_ptr< Foo > & foo_ptr, FooVector & vec )
{
   vec.clear();

   for( unsigned int i=0; i<100; i++ )
     {
       vec.push_back( foo_ptr );
     }
}


void print_use_count( shared_ptr< Foo > & ptr ) {
   cout << "[print_use_count] use_count=" << ptr.use_count()
        << " addr=" << std::ios::hex << ptr.get()
        << endl;
}


void print_use_count_const( const shared_ptr< Foo > & ptr ) {
   cout << "[print_use_count] use_count=" << ptr.use_count()
        << " addr=" << std::ios::hex << ptr.get()
        << endl;
}

////////////////////////////////////////////////////////////////////////
// -*- C++ -*-
//
// export_tst.cpp
//

#include "boost/shared_ptr.hpp"
#include "boost/python.hpp"
#include "boost/python/suite/indexing/vector_indexing_suite.hpp"

#include "tst.hpp"

namespace bp = boost::python;

BOOST_PYTHON_MODULE(_tst){

   bp::class_< std::vector< boost::shared_ptr<Foo> > >("vector_Foo")
     .def( bp::vector_indexing_suite< ::std::vector< boost::shared_ptr<Foo> >, 
true >() );


   { //::Foo
     typedef bp::class_< Foo, boost::shared_ptr< Foo > > Foo_exposer_t;
     Foo_exposer_t Foo_exposer = Foo_exposer_t( "Foo" );
     bp::scope Foo_scope( Foo_exposer );
     Foo_exposer.def( bp::init< >() );
     Foo_exposer.def_readwrite( "count", &Foo::count );
   }

   { //::build_vector

     typedef void ( *build_vector_function_type )( ::boost::shared_ptr< Foo > 
&,::FooVector & );

     bp::def(
             "build_vector"
             , build_vector_function_type( &::build_vector )
             , ( bp::arg("arg0"), bp::arg("arg1") ) );

   }

   { //::print_use_count

     typedef void ( *print_use_count_function_type )( ::boost::shared_ptr< Foo > 
& );

     bp::def(
             "print_use_count"
             , print_use_count_function_type( &::print_use_count )
             , ( bp::arg("arg0") ) );

   }

   { //::print_use_count_const

     typedef void ( *print_use_count_const_function_type )( ::boost::shared_ptr< 
Foo > const & );

     bp::def(
             "print_use_count_const"
             , print_use_count_const_function_type( &::print_use_count_const )
             , ( bp::arg("arg0") ) );

   }
}

////////////////////////////////////////////////////////////////////////
// -*- C++ -*-
//
// main.cpp
//

#include <vector>
#include <boost/shared_ptr.hpp> #include "tst.hpp"

using namespace boost;


int main()
{
   shared_ptr< Foo > f( new Foo );
   FooVector vec;
   build_vector(f, vec);

   print_use_count(f);
   print_use_count_const(f);
}


########################################################################

#!/usr/bin/env python


import _tst


def main():

     f = _tst.Foo()
     vec = _tst.vector_Foo()
     _tst.build_vector(f, vec)

     _tst.print_use_count(f)
     _tst.print_use_count_const(f)

if __name__ == "__main__":

     main()

########################################################################
# Makefile
########################################################################

all: main _tst.so

%.os : %.cpp
 	g++ -c $< -o $@ -fPIC -I /usr/include/python2.5

libtst.so: tst.os
 	g++ -shared $< -o $@

main: main.os libtst.so
 	g++ $< -o $@ -L . -ltst

_tst.so: export_tst.os  libtst.so
 	g++ -shared $< -o $@ -lboost_python -L . -ltst 
########################################################################


$ ./main
[print_use_count] use_count=101 addr=80x1617010
[print_use_count] use_count=101 addr=80x1617010
$ ./main.py
[print_use_count] use_count=101 addr=80x121b2b0
[print_use_count] use_count=1 addr=80x121b2b0


Nicolas.



-- 
Nicolas Regnault Laboratoire de Physique Nucléaire et de Hautes Energies
4, place Jussieu - Tour 43 RdC - 75252 Paris Cedex 05  +33 1 44 27 73 29


More information about the Cplusplus-sig mailing list