Jump to content

Learning how to use C++11 shared pointers

JMK

1,344 views

I have implemented C++11 shared pointers into Leadwerks Game Engine 5 and the following program now works.  When you press the space key the box variable is set to NULL and the visible box on the screen disappears:

#include "Leadwerks.h"

using namespace Leadwerks;

int main(int argc, const char *argv[])
{
	auto window = CreateWindow();
	auto context = CreateContext(window);
	auto world = CreateWorld();

	auto camera = CreateCamera(world);
	camera->Move(0,0,-5);
	camera->SetClearColor(0,0,1);

	auto light = CreateDirectionalLight(world);

	auto box = CreateBoxModel(world);

	while (not window->Closed())
	{
		if (window->KeyHit(SpaceKey)) box = NULL;
		if (box) box->Turn(0, 1, 0);
		world->Update();
		world->Render(context);
	}
	return 0;
}

Shared pointers provide the ease of use of a memory-managed language like C# but run much faster because they aren't using full garbage collection.  The one thing you have to watch out for is circular references.  In the example below, neither a or b would ever be deleted from memory, since they reference each other:

class thing
{
	shared_ptr<thing> friend;
};

auto a = make_shared<thing>();
auto b = make_shared<thing>();
a.friend = b;
b.friend = a;
a = NULL;
b = NULL;

This problem can be solved by using weak pointers:

class thing
{
	weak_ptr<thing> friend;
	shared_ptr<thing> GetFriend();  
};

shared_ptr<thing> thing::GetFriend()
{
	return friend.lock();
}

auto a = make_shared<thing>();
auto b = make_shared<thing>();
a.friend = b;
b.friend = a;
a = NULL;
b = NULL;

When using shared pointers you need to think about hierarchical relationships.  For example, a parent entity stores a list of shared pointers for its child entities, but each child uses a weak pointer to store its parent.  This makes it so children will not be deleted as long as you hold onto the parent entity:

class Entity
{
	std::list<shared_ptr<Entity> > kids;
	weak_ptr<Entity> parent;
};

These relationships are not always immediately obvious.  For example you might think that a world should control when entities are in scope, but that would not allow our first example above.  Instead, entity creation functions return a shared_ptr and the world octree only stores weak_ptr values to entities.  When you want to delete an entity, just set it to NULL.  If you have large collections of entities you can just store them in a list and clear the list when you are ready.  There is no World::Clear() function since the entities are managed by your own code.  I'm not 100% sure on how map loading will work with this, but so far it is working out well.

One thing to watch out for is that Self() or shared_from_this() cannot be accessed in the object constructor or destructor.  This will require some changes to how Leadwerks handles destruction of some objects, since previous versions uses manual deletion and removed lots of list iterators from different parts of the game world.  You might run into situations where you have a lot of weak pointers stored in lists like this:

for (std::list<weak_ptr<Entity> > it = list.begin(); it!=list.end(); it++)
{
	auto entity = (*it).lock();
	//do some stuff
}

Here is how you can modify the loop to handle the situation where an expired weak pointer is encountered (the object was deleted):

std::list<weak_ptr<Entity> > it = list.begin();
while (it != list.end())
{
	auto entity = (*it).lock();
	if (entity == NULL)
	{
		list.erase(it++);
		continue;
	}
	//do some stuff
	it++;
}

This will skip deleted objects and trim the list so that it doesn't grow out of control.

The new paradigm of C++11 shared pointers requires a little bit different approach but is much easier to use and does a good job of preventing mistakes especially when your game gets more complex.



1 Comment


Recommended Comments

Thanks for the info.   Been looking a little more seriously at C++ in Leadwerks. The v5 stuff sounds great, potentially simplifying things a bit for beginners which is certainly attractive.

 

 

Share this comment


Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

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.

×
×
  • Create New...