[C++-sig] Passing ownership to C++ through pointer

Jim Bosch talljimbo at gmail.com
Wed Nov 9 03:16:07 CET 2011


I think stepping through this with a debugger is indeed the best way to 
figure out what's going on.  I'm afraid there's both too little and too 
much information here for me to take a good guess at what the problem is.

I will say that exposing std::vectors of raw pointers to Python seems 
like a very scary thing to do, in terms of ensuring that you have the 
right memory management happening.  Weird bugs can happen when things 
get destroyed unexpectedly.

If the context you're running this code permits, I'd also recommend 
running this through valgrind.

Jim



On 11/08/2011 08:11 PM, Jay Riley wrote:
> Okay I think something else is majorly wrong; my component objects are
> being seen at Item onjects. I'll try to keep the code I show to a minimum.
>
> In my python file, I have the following:
>
> def ItemFactory(ItemNode):
> ItemName = ItemNode.attrib["name"]
> if (True):
> #if ItemName == "Elixir":
> CurrentItem = Item(ItemName)
> print ItemName
> componentNode = ItemNode.find("Components");
> if (componentNode != None):
> components = componentNode.getchildren()
> for component in components:
> if component.tag == "HealingComponent":
> healer = UseComponent("HealUseModule", True, True)
> print "Adding Healing Component"
> CurrentItem.RegisterComponent("Healing Component", healer)
> ItemModule.ItemLibrary.AddItem(CurrentItem)
>
> ItemNode is just an XML node that I parse for properties. Each Item node
> gets sent to this function. As per Jim's advice, RegisterComponent looks
> as follows:
>
> void RegisterComp(Items::Item& item, const std::string& compName,
> std::auto_ptr<UseComponentWrap> comp)//, void* comp)
> {
> item.RegisterComponent(compName, comp.get());
> comp.release();
> }
>
> Now, the components are registering. The problem is, when I try do the
> following:
>
> try
> {
> boost::shared_ptr<Items::Item> item =
> Game.GetItemLibrary().GetItem("Elixir");
> Components::Component* heal = item->GetComponent("Healing Component");
> Components::UseComponent* healertrue =
> dynamic_cast<Components::UseComponent*>(heal);
> if (healertrue != nullptr)
> healertrue->Use(std::vector<Character::BaseCharacter*>(),
> std::vector<Character::BaseCharacter*>());
> }
> catch (boost::python::error_already_set)
> {
> PyErr_Print();
> }
>
> it prints out this error:
>
> AttributeError: 'Item' object has no attribute 'Use'
>
> this is really confusing. How could my UseComponent have become an Item?
>
> I was testing it, and set the AddItem function as:
>
> static std::vector<Components::Component*> test;
> void ItemDatabase::AddItem(boost::shared_ptr<Item> item)
> {
> if (item.get() != nullptr)
> {
> IDToItemMap[item->GetID()] = item;
> NameToItemMap[item->GetName()] = item;
> auto healComp = item->GetComponent("Healing Component");
> if (healComp != nullptr)
> {
> test.push_back(healComp);
> int x = 10;
> }
> }
> }
>
> Here's the weird thing. While I'm adding items, I used x = 10 as a
> breakpoint to watch healComp's be added to test. The first healComp
> get's inserted correctly, and the PyObject's tp_name says UseComponent.
> When the second item with a healComp is being added, I used the vector
> to check the first healComp inserted and it somehow became an item
> (tp_name says Item). This is really weird. I thought it might be a
> scoping problem in my python code, but I can't see anything wrong with
> it. I'm not sure if it's relevant, but I'm including my UseComponent
> wrapping
>
> //Class definition
> class UseComponentWrap : public Components::UseComponent
> {
> public:
> UseComponentWrap(PyObject* self_);
> UseComponentWrap(PyObject* self_, const std::string& name, bool hasUse,
> bool hasBattleUse);
> UseComponentWrap(PyObject* self_, const Components::UseComponent& cmp);
> bool Use(std::vector<Character::BaseCharacter*>& Users,
> std::vector<Character::BaseCharacter*>& Targets) override;
> bool UseDefault(std::vector<Character::BaseCharacter*>& Users,
> std::vector<Character::BaseCharacter*>& Targets);
> bool BattleUse(std::vector<Battle::BattleCharacter*>& Users,
> std::vector<Battle::BattleCharacter*>& Targets, Battle::BattleField*
> field) override;
> bool BattleUseDefault(std::vector<Battle::BattleCharacter*>& Users,
> std::vector<Battle::BattleCharacter*>& Targets, Battle::BattleField* field);
> Components::UseComponent::ClonePtr Clone() const override;
> Components::UseComponent::ClonePtr CloneDefault() const;
> PyObject* self;
>
>
> private:
>
> };
>
> //Python Wrapping
>
> class_<Components::UseComponent, std::auto_ptr<UseComponentWrap>,
> bases<Components::Component> >("UseComponent")
> .def(init<>())
> .def(init<const std::string&,bool, bool>())
> .def(init<const Components::UseComponent&>())
> .def("BattleUse", &Components::UseComponent::BattleUse,
> &UseComponentWrap::BattleUseDefault)
> .def("Use", &Components::UseComponent::Use, &UseComponentWrap::UseDefault)
> .def("HasUse", &Components::UseComponent::HasUse)
> .def("HasBattleUse", &Components::UseComponent::HasBattleUse)
> .def("Clone", &Components::UseComponent::Clone,
> &UseComponentWrap::CloneDefault,
> return_value_policy<reference_existing_object>())
> .def("__copy__", &generic__copy__<Components::UseComponent>)
> .def("__deepcopy__", &generic__deepcopy__<Components::UseComponent>)
> ;
>
> I really don't see how this can get turned into an Item, Any ideas?
>
> Thanks for the help so far
>
>  > Date: Tue, 8 Nov 2011 11:02:23 -0500
>  > From: talljimbo at gmail.com
>  > To: cplusplus-sig at python.org
>  > Subject: Re: [C++-sig] Passing ownership to C++ through pointer
>  >
>  > On 11/08/2011 01:12 AM, Jay Riley wrote:
>  > > I'm trying to pass an object from python to C++. I want C++ to take
>  > > control of the object.
>  >
>  > <snip>
>  >
>  > > Am I doing something wrong? base on that snippet it should work. Is
>  > > there another way to do this? I know I should probably switch to
>  > > smart_ptrs and I'm considering it, but Id like to be able to know
> how to
>  > > do this, even if its just for future reference. Any help would be
>  > > appreciated.
>  > >
>  >
>  > I suspect the inheritance is getting in the way, and Boost.Python isn't
>  > being as smart as it could be about converting auto_ptr<T> to
>  > auto_ptr<U> when T* is convertible to U*.
>  >
>  > You might want to try having your register function wrapper accept
>  > auto_ptr<UseComponentWrap> (and if necessary, providing an overload that
>  > takes auto_ptr<UseComponent>).
>  >
>  > Before that, however, you might want to just try using "auto_ptr &"
>  > rather than simple "auto_ptr". It'd be unfortunate if that was
>  > necessary, but it's a possibility.
>  >
>  > Good luck!
>  >
>  > Jim
>  > _______________________________________________
>  > Cplusplus-sig mailing list
>  > Cplusplus-sig at python.org
>  > http://mail.python.org/mailman/listinfo/cplusplus-sig
>
>
> _______________________________________________
> Cplusplus-sig mailing list
> Cplusplus-sig at python.org
> http://mail.python.org/mailman/listinfo/cplusplus-sig



More information about the Cplusplus-sig mailing list