ClanLib SDK

Memory Management

ClanLib provides several different kinds of memory management interfaces. They can be roughly divided into two different categories:

Memory Management

ClanLib currently has two memory management classes; CL_DataBuffer and CL_SharedPtr<Type>.

CL_DataBuffer is a class that helps allocating a block of memory and freeing the memory when all references to the buffer is gone. A simple usage example where we retrieve job information from the Windows spooler:

DWORD size_required = 0;
GetJob(printer, job_id, 2, 0, 0, &size_required);
CL_DataBuffer buffer(size_required);
GetJob(printer, job_id, 2, buffer.get_data(), buffer.get_size(), &size_required);
JOB_INFO_2 *job_info = (JOB_INFO_2 *) buffer.get_data();
CL_Console::write_line("Document was printed by %1", job_info->pUserName);

The main point of using the data buffer class is that it is guaranteed that the above code will free the memory for JOB_INFO_2 no matter what exit path used, including any exceptions thrown.

The CL_SharedPtr template is an improved smart pointer. The idea is roughly the same as above with the data buffer class, except it uses C++ templates to allow you to treat the CL_SharedPtr as if it was a normal pointer. A simple example:

class MyClass
{
public:
	int a;
	void test() { }
};

CL_SharedPtr<MyClass> ptr(new MyClass);
ptr->a = 314;
ptr->test();

Once again same principle; when all references to the shared pointer is gone the instance of MyClass will be deleted.

The shared pointer template in ClanLib includes a number of tricks to avoid heap allocations and it allows you to fine-tune what is to be done when the references reach zero. In the above example, the only heap allocation was the 'new MyClass' command. Here's a more advanced example where we use a callback when it is time to free our class:

class MyOtherClass
{
public:
	void free_myclass(MyClass *ptr)
	{
		delete ptr;
	}
};

MyOtherClass other_class;
CL_SharedPtr<MyClass> ptr(
	new MyClass,
	&other_class, MyOtherClass::free_myclass);
ptr->a = 314;

We can also use the built-in memory allocator interface in ClanLib to allocate and free the memory. In this example we allocate the object on the stack using a 16 kilobyte fixed memory pool:

CL_FixedMemoryPool<16*1024> memory_pool;
CL_SharedPtr<MyClass> ptr(cl_new(&memory_pool) MyClass, &memory_pool));
ptr->a = 314;

Controlling your memory like this allows your application to vastly improve allocation performance, especially in multithreaded environments.

The reference counting in CL_SharedPtr does not support circular references; i.e. when object A has a pointer to object B and object B has a pointer to A. To solve this problem, the CL_WeakPtr<Type> template class is available:

class A
{
public:
	CL_SharedPtr<B> b;
};
class B
{
public:
	CL_WeakPtr<A> a;
};

CL_SharedPtr<A> a(new A);
a->b = CL_SharedPtr<B>(new B);
a->b->a = a;

When all references to A are gone, B is freed as well. But losing all references to B will not free A.

One last feature of CL_SharedPtr allows you to place any CL_SharedPtr object with the non-template class CL_UnknownPtr. You can then later 'cast' the object back into a CL_SharedPtr. If the object does not match the shared pointer type, the shared pointer will end up pointing at null.

CL_SharedPtr<A> a(new A);
CL_SharedPtr<B> b;
CL_SharedPtr<A> c;
CL_UnknownPtr unknown = a;
b = unknown; // b.is_null() returns true
c = unknown; // c now points at a

Allocators

ClanLib implements a replacement for the conventional operator new, delete and delete[]:

These replacements will use the CL_MemoryPool object passed to allocate and free the specified memory, instead of using the generic heap allocator provided with the compiler. This allows an application to much better fine-tune its memory allocations; an application could use different memory pools for temporary and persistent data, it could use different pools for each thread and so on.