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: tallji...@gmail.com
 > To: cplusplus-sig@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@python.org
 > http://mail.python.org/mailman/listinfo/cplusplus-sig


_______________________________________________
Cplusplus-sig mailing list
Cplusplus-sig@python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig

_______________________________________________
Cplusplus-sig mailing list
Cplusplus-sig@python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig

Reply via email to