[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