Jump to content
Search In
  • More options...
Find results that contain...
Find results in...

Leadwerks Company Blog

  • entries
    179
  • comments
    1,161
  • views
    337,333

Contributors to this blog

A look at C++11 Weak Pointers in Leadwerks 5


Josh

1,117 views

Previously, I talked a little bit about shared pointers in C++11.  These use automatic reference counting to track how many variables are pointing to an object.  When the object is no longer being used, it is automatically deleted.  This is similar to garbage collection, but doesn't involve the massive overhead of garbage-collected systems.  In fact, shared pointers simply automate something we were already doing with the Release() and AddRef() commands in Leadwerks 4.

A weak pointer is like a shared pointer, but having a weak pointer to an object does not prevent the object from being deleted.  Weak pointers are a great way to handle situations that previously could have resulted in an invalid pointer.  Let's say you have an AI class for an enemy in your game that stores an entity it is attacking:

class Monster : public Actor
{
	int health;
	weak_ptr<Entity> target;
  
	virtual void UpdateWorld();
};

To make use of the weak pointer, we convert it into a shared pointer.  At that point, the temporary shared pointer will prevent the object from being deleted:

void Monster::UpdateWorld()
{
	shared_ptr<Entity> enemy = this->target.lock();
	if (enemy != nullptr)
	{
		//do some stuff
	}
}

If something causes the monster's target entity to be deleted, the program will work just fine without having to go through and find all variables that point to that entity.

You can check if a weak pointer's object has been deleted with the expired() command, since creating a new shared pointer involves a certain amount of overhead:

void Monster::UpdateWorld()
{
	if (!this->target.expired())
	{
		shared_ptr<Entity> enemy = this->target.lock();
		if (enemy != nullptr)
		{
			//do some stuff
		}
	}
}

However, you still need to perform the check to see if the resulting shared pointer is nullptr/NULL because theoretically another thread could have caused the object to be deleted right after the expired() call returns false.

If you want to clean up a list of weak pointers as you discover expired pointers, you can structure it like this:

auto it = items.begin();
while (it!=items.end())
{
	auto item = (*it).lock();
	if (item != nullptr)
	{
		item->Update();
		it++;
	}
	else
	{
		items.erase(it++);
	}
}

If we add in the optional expired() check, it gets kind of complicated, but this is not something you should really need to do much:

auto it = items.begin();
while (it!=items.end())
{
	if (!(*it).expired())
	{
		auto item = (*it).lock();
		if (item != nullptr)
		{
			item->Update();
			it++;
		}
		else
		{
			items.erase(it++);
		}
	}
	else
	{
		items.erase(it++);
	}
}

Here's a real example in the Leadwerks source code.  The LEADWERKS_5 preprocessor definition is used to modify behavior in 4/5.  In version 4 the list contains pointers, and in version 5 it contains weak pointers:  Version 4 could get complicated because the entity would have to store an iterator to remove it from this list, in case it is deleted before this routine is called inside the World::Update() function.  In version 5 we just check if the weak pointer is valid and skip it if the entity was deleted.  At the end of the routine, the whole list is cleared, so there are no worries about deleting each iterator.

bool World::UpdateNavigation()
{
	//Invalidate navmesh tiles that intersect moved entities
	for (auto it = updatenavigationlist.begin(); it != updatenavigationlist.end(); it++)
	{
#ifdef LEADWERKS_5
		auto entity = (*it).lock();
		if (entity == nullptr) continue;
#else
		auto entity = (*it);
#endif
		entity->updatenavigationneeded = false;
		for (int i = 0; i<entity->relevantnavtiles.size(); i++)
		{
			entity->relevantnavtiles[i]->Invalidate();
		}
		entity->relevantnavtiles.clear();
		if (entity->navigationmode) navmesh->InvalidateTiles(entity->aabb);
	}
	updatenavigationlist.clear();

	//Update the navmesh
	return navmesh->Update();
}

Weak pointers make game programming easier and less susceptible to errors in Leadwerks Game Engine 5.

1 Comment


Recommended Comments

Guest
Add a comment...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Facebook Twitter Youtube Github Steam
×
×
  • Create New...