Jump to content

  • Log In with Google      Sign In   
  • Create Account

pointer behaviour


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
7 replies to this topic

#1 AlanSmithee   Members   -  Reputation: 1060

Like
0Likes
Like

Posted 06 May 2012 - 07:07 AM

Hi.

So I came across (what I think is) some wierd pointer behaviour and I was hoping someone around here might be able to explain this behaviour.

1. In the AIObject class I have a public static container that holds various AI entities, such as NPCs or monsters etc.
std::vector<AIObject*> AIObjects;

2. (In the player class I have a target)
DynamicObject* target;

3. When targeting an enemy the target is set:
this->target = AIObject::AIObjectList[activeTarget];
(There's actually a bit more in to selecting the target, but it's unrelated to this problem)

4. You are then able to do various things like casting a spell:
void Player::cast_spell(int type)
{
	if (target != 0)
		spells.push_back(new Spell(type, this, target));
}


Up to this point it works as I would imagine it should.
For instans, if I switch target it changes the target accordingly and if the target moves out of the screen it gets de-selected and so on.

But whenevever a target gets removed from the AIObjects vector the target member inside the Player class isn't updated accordingly.

5. In the main-loop:
if (!AIObject::AIObjects[i]->is_alive())
{
	delete AIObject::AIObjects[i];
	AIObject::AIObjects[i] = 0;
	AIObject::AIObjects.erase(AIObject::AIObjects.begin() + i);
}

6. But in the player class:
void Player::show_active_target()
{
	if (target != 0)
	{
		// this still gets exectued
	}
}

I was under the impression that since the target pointer in the Player class is pointing to an AIObject in the AIObjects vector if the AIObject being pointed at were to get deleted so would the pointee?

I've found a work-around:
if (target != 0)
	if (!target->is_alive())
		target = 0;

But this isn't a very elegant solution and I would much rather understand why the target pointer isn't updated accordingly.
(For the record, Player and AIObject share the same base-class (DynamicObject) and the actual target is of type Monster which is a derrived class of AIObject.)

Thanks in advance for your help! / AS.

Sponsor:

#2 SiCrane   Moderators   -  Reputation: 9668

Like
2Likes
Like

Posted 06 May 2012 - 07:17 AM

I was under the impression that since the target pointer in the Player class is pointing to an AIObject in the AIObjects vector if the AIObject being pointed at were to get deleted so would the pointee?

Why would it? The vector stores a copy of the pointer you pushed into it. No operation on the pointer in the vector will affect any other pointers in the program. It's like how if you store an int in the vector, operating on the int in the vector won't affect any other int in the program.

#3 Rattenhirn   Crossbones+   -  Reputation: 1808

Like
1Likes
Like

Posted 06 May 2012 - 07:19 AM

If you delete an object, not all pointers to it are automatically set to 0. This would be very convenient, but that's not how it works.

The simplest, but also pretty dangerous solution would be to manually set every reference to the deleted object to 0 manually.

Alternatively, you can add another layer of abstraction, i.e. a "shared_ptr". This would ensure, that as long as something is pointing to the object, it does not get deleted. This is probably not what you want, but there's also a standard solution for that. For references that should not keep the object alive, use "weak_ptr".

Here's a quick tutorial that google spat out after a quick search:
http://cppguru.wordpress.com/2009/01/05/c-weak-pointers/

I hope that helps!

#4 AlanSmithee   Members   -  Reputation: 1060

Like
0Likes
Like

Posted 06 May 2012 - 07:42 AM

Hi guys, thanks for your quick reply.

Ah SirCrane, makes a lot of sense. I think that I was thinking about it backwards.. The target pointer in the player class affects the one in the AIObjects vector but not the other way around.. I see it more clearly now Posted Image

Rattenhirn, thanks! I am aware of shared_ptr but I've only used them for the ownership or reference counting properties.

Alternatively, you can add another layer of abstraction, i.e. a "shared_ptr". This would ensure, that as long as something is pointing to the object, it does not get deleted. This is probably not what you want, but there's also a standard solution for that. For references that should not keep the object alive, use "weak_ptr".


Aha! So by this I guess the AIObjects vector would be:
std:.vector<std::tr1::shared_ptr<AIObject> > AIObjects
And the target-pointer in the Player class:
std:.vector<std::tr1::weak_ptr<AIObject> > target
?

I'll check that tutorial out right away.

Thanks again guys Posted Image

Edited by AlanSmithee, 06 May 2012 - 07:43 AM.


#5 Rattenhirn   Crossbones+   -  Reputation: 1808

Like
0Likes
Like

Posted 06 May 2012 - 02:16 PM

Looks ok, but in you original code, "target" was just a single pointer and now it's a vector of pointers.

#6 AlanSmithee   Members   -  Reputation: 1060

Like
0Likes
Like

Posted 07 May 2012 - 01:04 AM

Ah was a typo, sorry ^_^

#7 Ameise   Members   -  Reputation: 766

Like
0Likes
Like

Posted 07 May 2012 - 11:39 AM

Ah SirCrane, makes a lot of sense. I think that I was thinking about it backwards.. The target pointer in the player class affects the one in the AIObjects vector but not the other way around.. I see it more clearly now Posted Image


That still doesn't sound like you're "getting it". Neither pointer effects one another; both the pointer that is stored as a field in the player instance, and the pointer that is stored in the vector, are just pointers. They are just integers, who happen to be storing the memory address of some object instance in memory. When performing operations on those pointers, you are altering that instance. If you set the pointer that is a field to nullptr, such will not change the one in the vector, and vice versa.

Your initial solution is dangerous and undefined behavior. Why?
if (!target->is_alive())

You've already deleted the object that 'target' points to. If is_alive happens to work, great, but it's still undefined and shouldn't be relied upon. Once the memory where 'target' points to is overwritten, that will no longer function properly.

The proper two ways are (as has already been said):

A, Send out some kind of signal to objects that said object has been deleted, so that they may remove references to it.
B, Use the shared_ptr/weak_ptr paradigm.

EDIT: I missed a word.

#8 AlanSmithee   Members   -  Reputation: 1060

Like
0Likes
Like

Posted 08 May 2012 - 04:13 PM

Hi Amesie.
Thanks for taking your time to clarify this.

I had a fealing I still wasn't understanding it properly, becaus when I thought something would act according to my prior statement, it did not.

I had some problems implementing the weak_ptr/shared_ptr paradigm so I did some testing with a simple class hierarchy in a console enviroment passing around shared_ptr's and managing them via weak_ptr's inside the class objects and now I finally understand how it works and how well that design would fit my needs so I'm going to implement it tomorrow!

Thanks again folks =)

Edit: bird?

Edit 2: Got it working now with the smart pointers so woho~ =)

Edited by AlanSmithee, 09 May 2012 - 12:35 PM.





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS