Boost logo

Boost Users :

Subject: Re: [Boost-users] revisiting casting a boost::shared_ptr to void*
From: Gavin Lambert (gavinl_at_[hidden])
Date: 2014-07-30 00:33:52


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.


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net