This is the homepage of Peter Alexander. I am currently at Facebook working on Core Data. Previously a game developer at Codemasters. Any opinions are my own.
- unique_ptr Type Erasure
- The Condenser Part 1
- Cube Vertex Numbering
- Range-Based Graph Search in D
- Ranges Part 1 - Basics
unique_ptr Type Erasure
Often when building APIs we’d like the caller to provide some information in
a format, or using a protocol defined by the library. For example, we might
want access to a contiguous buffer specified by a (
An API like this is fine if the buffer will be read synchonously, but sometimes we need asynchronous access. This introduces a lifetime problem: how does the caller know when it can free the buffer?
A common way to solve this is to provide a callback that will be invoked once the processing has completed:
done will be called with
cool_feature has asynchonously
finished its work.
This works most of the time, but has a couple of problems:
- You need to remember to call
donein all cases.
- It only works if done only needs to be called with the buffer pointer. What if my buffer is part of a larger object?
There’s no obvious choice of function to pass in. We want to free
buffer processing is done, but we’ll be given a pointer to the string data, not
A possible solution is to pass in an
std::function<void()> as the callback,
obj can be captured and destroyed as necessary. This works, but
std::function has difficulty with move-only types, and there’s no guarantees
that a capturing
std::function won’t allocate memory.
We could, of course, define another interface (maybe call it
ContiguousBufferProvider), but this also requires an extra memory allocation.
A little trick we can do to handle most of the common cases is to pass in
context to the function.
The context is essentially an extra piece of baggage that must be carried around until the buffer has been processed. Once processed, we just drop the context and it cleans up after itself.
We can also benefit from an extra function that converts any object into
Context through type erasure:
With this, the
Object example is easy to solve:
This guarantees no extra memory allocations, and
cool_feature just needs to
drop the context once finished.
There are probably more general ways to solve this, but I like this approach as it is clean, simple, and solves all the problems I’ve encountered so far.