World Object Memory Managment

Started by
6 comments, last by ApochPiQ 12 years, 1 month ago
Currently my memory managment here is a bit of a mess and has some issues with circular references and such.

The primary issue is that many objects need to reference each other, and they need to store these references. The issue here is when an object dies, how to cleanup all these references (e.g. incoming projects might have a target reference to it, whatever unit was attacking it, a unit it was attacking might have stored an attackedBy reference, etc).


The only solution I could think of was to make break away from the idea that an object is deleted at the point it is destroyed.

  • Make the objects reference counted, to prevent deletion while still referenced by somthing.
  • Have a kill() method that is called when the unit is killed. This nulls out all references to other objects, and sets the alive flag to false.
  • Have an isAlive() method for other objects to use to see if the object they are referencing is still alive. If not, they should release that reference and carry on (e.g. attempt to find somthing else to shoot at instead)


This seems perfectly viable to me. However I get the impression from a number of bits of code Ive seen around or people have talked about that this is not actually how the problem is generally solved. However I can't personally see another solution that doesnt involve essentially reference counting every object in the game world. Is there another way? I guess there is also a performance impact (not really worked out how many references get aquired/releashed per update step yet)?


[source lang="cpp"]
class WorldObject : public MakeRefCountedSomehow
{
public:
WorldObject():alive(true){}
virtual ~WorldObject()
{
assert(!alive);
}
bool isAlive()const {return alive;}
virtual void kill()
{
alive = false;
};
private:
bool alive;
};
class Unit : public WorldObject//likly some other classes inbetween
{
public:
virtual void kill()
{
target = 0;
WorldObject::kill();
};
private:
ref_ptr<Unit> target;
bool alive;
...other stuff...
};

[/source]


On an implementation note and not reinventing the wheel. I never really liked shared_ptr with how it adds reference counting to a class that is otherwise not reference counted. There is intrusive_ptr, but is there existing and tested code for the reference counter itself (put somthing together with interlocked increment/decrement and initial ref count of 1 already if not)?
Advertisement
shared_ptr and weak_ptr are probably the most straightforward solution to your situation.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

The only solution I could think of was to make break away from the idea that an object is deleted at the point it is destroyed.
Yes, this is necessary. I recall a case in which the game (developed in Java) incorrectly assumed that destruction == deletion. That was sort of admissible in C++, but not in Java. As a result there were a few issues.
In C++, I still think it's absolutely required to have a two-step destruction for some entity types. In no case an entity could be assumed alive just because it's there.
In short, I strongly encourage you in thinking in that direction.

Previously "Krohm"

You could have an interface for all objects that can be referenced, and when one object references another, it gives it that interface. When an object dies/gets removed from the game, it would call those interfaces and notify the objects referenceing them it's dead.

Something like this:


class IReferer
{
public:
virtual ~IReferer() {}
virtual void ObjectRemoval(TBaseObject &ObjectBeingRemoved);
};

class TPlayer : public TBaseObject,
public IReferer
{
public:
...
void ObjectRemoval(TBaseObject &ObjectBeingRemoved);
...
private:
TBaseObject &TargetObject;
}

TPlayer::SetTargetObject(TBaseObject &ObjectToTarget)
{
TargetObject = ObjectToTarget;

// Tell object we're refering to it
TargetObject.Addreferer(this);
}

TBaseObject::AddReferer(IReferer &Referer)
{
RefererList.push_back(Referer);
}

// TEnemy inherits from TBaseObject
TEnemy::Kill()
{
// loop through list of referers and notify them we're leaving soon
for (it = RefererList.begin(); it != RefererList.end(); it++) {
it->ObjectRemoval(this);
}
}


This was just a thought, and I've never used it, but maybe you can glean some ideas from it.

My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)


This was just a thought, and I've never used it, but maybe you can glean some ideas from it.

So if you never used it, how have you solved the memory managment problem?

[quote name='BeerNutts' timestamp='1331911627' post='4922601']
This was just a thought, and I've never used it, but maybe you can glean some ideas from it.

So if you never used it, how have you solved the memory managment problem?
[/quote]

I'm sorry, but are you saying, when thinking of solutions, only if I've done them directly can I comment on them?
I was throwing out ideas, trying to give you other options. If you don't like them, fine, but don't be a jack-arse about it.

I've solved it by marking items Active and Inactive, and, before going through main loop, I remove all inactive object.
However, I haven't used any sort of system that notifies anyone who is referencing the deleted object.

You're welcome.

My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)


I'm sorry, but are you saying, when thinking of solutions, only if I've done them directly can I comment on them?
I was throwing out ideas, trying to give you other options. If you don't like them, fine, but don't be a jack-arse about it.

No, I'm saying if you used a completly different approach, Id like to know what that approach is, and not just take my idea as "the solution" (your post implied you had used some alternate solution to an alive flag and ref counting scheme that turned out to be viable


I've solved it by marking items Active and Inactive, and, before going through main loop, I remove all inactive object.
However, I haven't used any sort of system that notifies anyone who is referencing the deleted object.
).
Seems viable, since with my referencing counting I'm still aiming to delete the object as soon as possible. Could have like a pre-update loop that lets everything detect and remove dead references while there still valid (so remove the refcounter/shared_ptr, keep isAlive or such a before delete loop).
I still see nothing here that can't be trivially solved with shared_ptr and weak_ptr.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

This topic is closed to new replies.

Advertisement