Jump to content

Leadwerks News

  • entries
    190
  • comments
    1,264
  • views
    769,975

Contributors to this blog

A Look at C++11 Shared Pointers in Leadwerks 5


C++11 introduces shared pointers, a powerful language feature that provides easy memory management without the overhead of garbage collection.  The example below should look familiar to you:

#include "Leadwerks.h"

using namespace Leadwerks;

int main(int argc, const char *argv[])
{
	shared_ptr<Leadwerks::Window> window = Leadwerks::Window::Create();

	shared_ptr<Context> context = Context::Create(window);

	shared_ptr<World> world = World::Create();

	shared_ptr<Camera> camera = Camera::Create();
	camera->SetRotation(35, 0, 0);
	camera->Move(0, 0, -6);

	shared_ptr<Light> light = DirectionalLight::Create();
	light->SetRotation(35, 35, 0);

	shared_ptr<Model> model = Model::Box();
	model->SetColor(1.0, 0.0, 0.0);
	model->SetPosition(-4, 0, 0);

	while (true)
	{
		if (window->Closed() || window->KeyDown(Key::Escape)) return false;
		
		Leadwerks::Time::Update();
		world->Update();
		world->Render();
		context->Sync();
	}
  
	//Everything will get automatically deleted when we return from this function
	return 0;
}

Using the auto keyword simplifies everything (and it makes this code compatible with Leadwerks 4):

#include "Leadwerks.h"

using namespace Leadwerks;

int main(int argc, const char *argv[])
{
	auto window = Leadwerks::Window::Create();

	auto context = Context::Create(window);

	auto world = World::Create();

	auto camera = Camera::Create();
	camera->SetRotation(35, 0, 0);
	camera->Move(0, 0, -6);

	auto light = DirectionalLight::Create();
	light->SetRotation(35, 35, 0);

	auto model = Model::Box();
	model->SetColor(1.0, 0.0, 0.0);
	model->SetPosition(-4, 0, 0);
	
	while (true)
	{
		if (window->Closed() || window->KeyDown(Key::Escape)) return false;
		
		Leadwerks::Time::Update();
		world->Update();
		world->Render();
		context->Sync();
	}
  
  	//Everything will get automatically deleted when we return from this function
	return 0;
}

Now things get interesting.  This function would normally cause a horrible memory leak, but with shared pointers everything is fine:

void SaveTexture(shared_ptr<Texture> tex)
{
	auto bank = Bank::Create(tex->GetMipmapSize());
	tex->GetPixels(bank->buf);
	bank->Save("pixeldata.dat");
}

Yet shared pointers can still equal nullptr:

auto bank = Bank::Create();
bank.reset();
Debug::Assert(bank==nullptr);

You can even simply set a shared pointer to nullptr, and if that was the last pointer that referenced it, it gets deleted!

auto bank = Bank::Create();
bank = nullptr;// auto deletion here!

How to Delete an Entity
The code below will not delete the entity, because a shared pointer is still stored in the world.

auto entity = Pivot::Create();
entity = nullptr;

The entity must be have its world set to NULL, and the shared pointer must be set to NULL or go out of scope:

entity = Pivot::Create();
entity->SetWorld(nullptr);
entity = nullptr;

Children use a weak pointer to the parent, so they will not cause self-referencing.

Asset Management
You no longer have to worry about calling Release() when loading assets:

auto material = Material::Create();
auto texture = Texture::Load("mytex.tex");
material->SetTexture(texture);
texture = nullptr;

Unused assets will automatically be deleted if they go out of scope:

auto material = Material::Create();
auto texture = Texture::Load("mytex.tex");
material->SetTexture(texture);
texture = nullptr;
material = nullptr;

But if they are in use, they will be retained in memory:

auto material = Material::Create();
auto texture = Texture::Load("mytex.tex");
material->SetTexture(texture);
model->SetMaterial(material);
texture = nullptr;
material = nullptr;

In conclusion, shared pointers automate many of the tasks we have been doing manually with the Leadwerks reference counting system and the AddRef and Release commands.

4 Comments


Recommended Comments

Josh

Posted

This feature is going to make the Leadwerks 5 editor a lot easier to write.

  • Upvote 1
martyj

Posted

I take it the above code examples means you've already started transitioning LE to shared pointers?

What happens if you call delete on a shared pointer? Will I also have to transition my code when migrating to LE 5.5?

Josh

Posted

13 minutes ago, martyj said:

I take it the above code examples means you've already started transitioning LE to shared pointers?

I am adding defines in the code so the Leadwerks 4 source can be compiled in both modes.  It's nowhere near functional, I just started experimenting with it.  The LEADWERKS_5 define will keep the v5 stuff from messing with the current version.

13 minutes ago, martyj said:

What happens if you call delete on a shared pointer? Will I also have to transition my code when migrating to LE 5.5?

They did a nice job with the implementation of this.  It looks like delete will just call the reset() function:
https://stackoverflow.com/questions/12321949/explicitly-deleting-a-shared-ptr

That means if this is the only handle to the object, the object will be deleted.  Otherwise, the shared pointer will just have its ref count decremented.  (In Leadwerks 4 you should be calling Release() on Leadwerks objects, not delete.)

Note that the Release() and AddRef() functions will not exist in Leadwerks 5.

Josh

Posted

23 minutes ago, jen said:

This is optional right? We can still use the traditional method of assigning a type for each variable in our projects? 

I prefer the traditional way to be honest. Especially when developing multiplayer.

The type is a shared pointer (instead of a pointer).  The first example above shows how it is done.  I prefer the auto keyword because it is less to type.

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...