This is the first in an on-going series of posts relating nuggets of D wisdom gained through daily praxis.
“this is a local variable”
I recently came across the situation where I needed to pass a pointer to an object to a callback function in a C library. The function was designed so that you can pass ‘additional data’ by means of a void*, which could be used to point to any kind of data in memory which would contain the context for the callback. This is a fairly common pattern in C libraries, designed to make the callbacks flexible and extensible to any use case.
Here’s a simplified example of the situation:
class MyClass
{
// Method to register a request with the C library, passing a reference
// to this object as the 'context', which will be passed to the C callback
// function below when the request is processed.
void register ( )
{
void* pointer_to_this /* = ? */;
CLibraryFunction(pointer_to_this);
}
// Callback
extern ( C ) static private void callback ( void* context )
{
// somehow cast the 'context' argument to an object reference
// and do something with it
}
}
So the question is, how to get the address of an object, from inside it, to pass to the C library function? And how to convert it back to a usable object reference inside the callback function?
My initial instinct was:
void* pointer_to_this = &this;
Sounds fair enough, right? But unfortunately it’s not that simple. After some research I turned up the fairly obscure fact that this is actually a local variable which is implicitly added to the every method’s parameter list. This means that by taking the address of this, all we get is a pointer to somewhere in the stack, which is not at all what was intended!
The solution is to think about what this actually is: a reference to an object. So we can cast the reference directly to a void*, and then cast it directly back – there’s no need to take the address of it or to dereference it at the other end using the * operator.
class MyClass
{
// Method to register a request with the C library, passing a reference
// to this object as the 'context', which will be passed to the C callback
// function below when the request is processed.
void register ( )
{
void* pointer_to_this = cast(void*)this;
CLibraryFunction(pointer_to_this);
}
// Callback
extern ( C ) static private void callback ( void* context )
{
MyClass object = cast(MyClass)context;
// do something with object
}
}
More D language “D-tails” to come.
Are you smart? Innovative? Driven? If you’re interested in working on challenging projects in one of the world’s most fast-paced industries, why not check out the openings on our Careers page?