[C++-sig] Boost::python and shared_ptr

Bernhard Glück bernhardprivat at realspace.org
Tue Jan 4 21:45:10 CET 2005


  Hi !

I am using a boost::python to script our newest project.
We use boost::shared_ptr for almost all of our objects.

How do i correctly wrap my classes so that they are held as shared_ptr 
objects and
passed around that way ? I tried doing it like it was posted this 
mailing list
before, but with the following problems.

My environment is as follows::

Python 2.4,
Boost 1.32.0
Compiler: VC7.1

Here the relevant code passages:

First our game object which holds smart pointers to several sub systems:

typedef boost::shared_ptr< class GraphicsServer >        GraphicsServerPtr;
     typedef boost::shared_ptr< class AudioServer > 
AudioServerPtr;
     typedef boost::shared_ptr< class ScriptServer > 
ScriptServerPtr;
     typedef boost::shared_ptr< class InputServer > 
InputServerPtr;
     typedef boost::shared_ptr< class PhysicsServer > 
PhysicsServerPtr;
     typedef boost::shared_ptr< class AiServer >                AiServerPtr;
     typedef boost::shared_ptr< class ConfigurationServer > 
ConfigurationServerPtr;
     typedef boost::shared_ptr< class TimeServer >            TimeServerPtr;

     class Game :    public Ogre::Singleton<Game>,
             public Ogre::FrameListener
     {
         public:

         const GraphicsServerPtr & GetGraphicsServer() const;
         const AudioServerPtr &      GetAudioServer() const;
         const ScriptServerPtr &      GetScriptServer() const;
         const InputServerPtr &      GetInputServer() const;
         const PhysicsServerPtr &  GetPhysicsServer() const;
         const AiServerPtr &      GetAiServer() const;
         const ConfigurationServerPtr &    GetConfigurationServer() const;
         const TimeServerPtr    & GetTimeServer() const;

         void            Start();
         void            Stop();

         bool    frameStarted(const Ogre::FrameEvent& evt);
         bool    frameEnded( const Ogre::FrameEvent & evt);

         Game();
         virtual ~Game();

         private:

         GraphicsServerPtr        mGraphicsServer;
         AudioServerPtr            mAudioServer;
         ScriptServerPtr            mScriptServer;
         InputServerPtr            mInputServer;
         PhysicsServerPtr        mPhysicsServer;
         AiServerPtr                        mAiServer;
         ConfigurationServerPtr    mConfigurationServer;
         TimeServerPtr        mTimeServer;

         bool            mStop;
     };

Now our configuration server code that stores "registry" style values (
configuration information for our game )

class ConfigurationServer : public Server
     {
         public:

         template<typename T>
         inline T GetValue( const std::string & name,T defaultValue )
         {
             if ( mValues.find(name) != mValues.end() )
             {
                 boost::any value = mValues[name];
                 if ( value.type() == typeid(T ))
                 {
                 return boost::any_cast<T>(value);
                 }
                 else
                 {
                 boost::format errorFmt("Configuration value
                                 (%1%) of wrong type (%2%),
                                 expected (%3%), using default of (%4%).");
                 errorFmt % name;
                 errorFmt % value.type().name();
                 errorFmt % typeid(T).name();
                 errorFmt % defaultValue;
                 Log( errorFmt.str() );
                 }
             }
             else
             {
                 boost::format errorFmt("Configuration value
                                 (%1%) not found, using default of (%2%).");
                 errorFmt % name;
                 errorFmt % defaultValue;
                 Log( errorFmt.str() );
             }
             return defaultValue;
         }

         template<typename T>
         inline void SetValue( const std::string & name,T value )
         {
             mValues[name] = boost::any(value);
         }

         virtual bool        Reset();
         virtual bool        Initialize();
         virtual bool        Shutdown();
         virtual bool        Update( float deltaTime );

         ConfigurationServer();
         virtual ~ConfigurationServer();

         private:

         std::map<std::string,boost::any> mValues;
     };

And now the export part:

///////////////////////////////////////////////////////////
void PyExportConfigurationServer()
{
     Log("Exported configuration server.");
     void (ConfigurationServer::*cm1)( const std::string &,int ) 
         =
&ConfigurationServer::SetValue;
     void (ConfigurationServer::*cm2)( const std::string
&,float)=&ConfigurationServer::SetValue;
     void (ConfigurationServer::*cm3)( const std::string &,bool )
=&ConfigurationServer::SetValue;
     void (ConfigurationServer::*cm4)( const std::string &,std::string )
=&ConfigurationServer::SetValue;

     register_ptr_to_python< boost::shared_ptr<ConfigurationServer> >();

     class_< ConfigurationServer,boost::shared_ptr<ConfigurationServer> >
("ConfigurationServer",no_init )
         .def("set",cm1)
         .def("set",cm2)
         .def("set",cm3)
         .def("set",cm4);
}

///////////////////////////////////////////////////////////
void PyExportGame()
{
DeepVoid::Log("Exported game.");
     class_<Game> ("Game",no_init )
         .def("quit",&Game::Stop )

.def("getConfigurationServer",&Game::GetConfigurationServer,
return_value_policy<reference_existing_object>());

     def("getGame",&Game::getSingleton,
return_value_policy<reference_existing_object>());

}


///////////////////////////////////////////////////////////
BOOST_PYTHON_MODULE(dv)
{
     PyExportConfigurationServer();
     PyExportGame();
}


The problem now is that the game class works as expected but whenever i do
something like this:

import dv
game = dv.getGame()
config = game.getConfigurationServer()
config.set("Graphics.Fullscreen",1)

I get the following error:

exceptions.TypeError
20:54:20: No Python class registered for C++ class class
boost::shared_ptr<class
DeepVoid::ConfigurationServer>
20:54:20:   File "DeepVoidConfig.py", line 3, in ?     config =
game.getConfigurationServer()


I have no clue why this could happen. I  tried chaning the export code 
for the
ConfiguratioNServer in various ways ( leaving out register_ptr_to_python,
or the second wrapper definition ) to no avail..

Both classes get exported by the way ( as my log tells me, thats why i have
those two Log statements in the code )....

So what can i do to pass around my objects as shared_ptrs ?
Ideally i would like almost all objects of our engine to be held in
shared_ptr instead of normal ones.

Hope anyone can help :-)
Thanks in advance
Bernhard Glück




More information about the Cplusplus-sig mailing list