[C++-sig] Object lifetime issue

Achim H. achim-bpl at mol-net.com
Mon Sep 3 11:02:04 CEST 2007


Hi,

I had a similar problem and all I could come up with was this memory-leaking 
approach using Py_INCREF(). Please note that I don't use the copy ctor but a 
special duplicate() function that creates a new object and does not make a 
copy:

template <class T> boost::python::object getOwner(T* tp)
{
	using namespace boost::python;
	// see http://article.gmane.org/gmane.comp.python.c++/9530
	return object ( handle<> ( borrowed ( 
detail::wrapper_base_::get_owner(*tp))));
}

/* virtual */ Base* BaseWrapper::duplicate() const
{
	BaseWrapper* orig = const_cast<BaseWrapper*>(this);
	object self = getOwner(orig);
	object OBJ = self.attr("__class__");
	object o = OBJ(); // ctor call
	BaseWrapper& obj = extract<BaseWrapper&>(o);
	BaseWrapper* dup = &obj;
	Py_INCREF(o.ptr());
	return dup;
}

It is still a kludge - maybe somebody else can propose a cleaner solution.
I'd be very interested.

Achim.

Am Sonntag 02 September 2007 schrieb Matt Holmes:
> I am trying to expose one of the classes in my engine as an abstract
> class that is used as the base for a series of Python classes.
>
> That class is called InputCommand and is defined as such:
> namespace Stasis {
> 	class InputCommand {
> 	public:
> 		virtual bool execute() = 0;
> 	};
> }
>
> To expose that class, I created the following wrapper:
>
> class InputCommandWrapper : public Stasis::InputCommand, public
> wrapper<Stasis::InputCommand> {
> public:
> 	bool execute() {
> 		return this->get_override("execute")();
> 	}
> };
>
> And added it to my Boost.Python module like so:
>
> class_<InputCommandWrapper, boost::noncopyable>("InputCommand")
> 	.def("execute", pure_virtual(&InputCommand::execute));
>
> Everything seems okay so far, but then I have another class called
> InputManager. This class exposes a function, registerCommand, that takes
> a const std::string& and an InputCommand*. That classes partial
> defintion is:
>
> class InputManager : public Singleton<InputManager>
> public:
> 	static InputManager& getSingleton() { return *ms_Singleton; }
> 	static InputManager* getSingletonPtr() { return ms_Singleton; }
>
> 	InputManager();
> 	~InputManager();
>
> 	void executeCommand(const string& cmdName);
> 	void registerCommand(const string& cmdName, InputCommand* cmd);
> }
>
> It is defined in the Boost.Python module as such:
>
> class_<InputManager>("InputManager")
> 	.def("registerCommand", &InputManager::registerCommand,
> with_custodian_and_ward_postcall<1, 3>())
> 	.def("getSingleton", &InputManager::getSingleton,
> return_value_policy<reference_existing_object>()).staticmethod("getSingleto
>n");
>
> I am executing the follwing Python script, which should create an
> instance of the QuitCommand object, pass it to the
> InputManagers::registerCommand method, which will store that command
> object and use it to execute the given command later (which is
> implemented in Python). The issue is that when I call the execute()
> method of my store InputCommand*, my program crashes. From what I can
> tell it's because Python is destroying the object I created in the
> Python script below to pass to registerCommand. I thought
> with_custodian_and_ward<1, 3> (the custodian should be 'this', the
> InputManader, and the ward should be the InputCommand sub-class object)
> would stop the Python GC from destroying it, but I guess I was wrong.
>
> Here is the Python script:
>
> from engine import *
>
> class QuitCommand(InputCommand):
>      def execute(self):
>          Kernel.getSingleton().shutdown()
>
> if __name__ == "__main__":
>      InputManager.getSingleton().registerCommand("Quit", QuitCommand())
>
> What am I doing wrong here? What do I need to do to tell Python "The
> QuitCommand() object I just created, don't destroy it, something else is
> holding a reference to it"?
>
> _______________________________________________
> C++-sig mailing list
> C++-sig at python.org
> http://mail.python.org/mailman/listinfo/c++-sig





More information about the Cplusplus-sig mailing list