
On 30/07/2014 15:32, Chris Cleeland wrote:
In my case, it's a multi-shot callback. I don't think I'd need to do a heap allocation/deallocation each cycle, but I'm also not sure that I want to do a heap allocation in the first place.
But you have to know what the C API is going to be doing with that pointer, or all bets are off.
In my case, the C API is stashing the value of the pointer in a container, and passing that pointer value as an argument to the registered callback function. That's it. The C code doesn't *do* anything with the pointer because it treats it as a void*.
You're going to need a heap allocation *somewhere*. I don't think there's any way you can avoid that. It's just a question of whether you already have an existing heap object with the right lifetime or whether you need to make a new one. For a multi-shot callback, you will need to have some raw pointer you can guarantee will remain valid from C API registration to unregistration. One way to do this would be to make an object responsible for registration/unregistration, which forces you to keep this object alive as long as you want the registration to last -- this means that this object can itself be the void* for your C API: class SomeExternalApiRegistration { public: SomeExternalApiRegistration() { RegisterSomeExternalApi( &SomeExternalApiRegistration::DoSomethingC, this); } ~SomeExternalApiRegistration() { UnregisterSomeExternalApi( &SomeExternalApiRegistration::DoSomethingC, this); } private: static void DoSomethingC(void *arg) { static_cast<SomeExternalApiRegistration*>(arg)->DoSomethingCpp(); } void DoSomethingCpp() { // ... } }; In order to actually do whatever it is this needs to, it can have shared_ptr or weak_ptr members, possibly even delegating all the work to them. Just remember that something has to own the above object, and if it's the same object that's going to get called, then you need a weak_ptr. (Things get trickier in a concurrent environment -- you have to know that unregistering will block until any in-progress calls are completed or cancelled, or hilarity may ensue.) I usually prefer doing something like the above as it nicely follows RAII. But you could instead allocate some functor/container object (or the shared_ptr itself) on registration, provide a similar invoker to the above, and deallocate the object on deregistration. But that ends up looking very similar, because you usually need a way to remember which object to deallocate on unregistration. I don't think doing it that way is useful unless you need something single-shot.