Reputation: 1458
I have an old C-style library that uses callback with unsigned long for user argument and I want to pass my shared_ptr to callback so that reference count is incremented.
void callback( unsigned long arg ) {
std::shared_ptr<my_class> ptr = ??? arg ???
}
void starter_function() {
std::shared_ptr<my_class> ptr = std::make_shared<my_class>();
unsigned long arg = ??? ptr ???
// pass to library so it may be used by callback
}
Currently I use get() on shared_ptr and then use C-style cast but this creates a problem when start_function goes out of scope.
Upvotes: 5
Views: 2908
Reputation: 29017
Create a static store (which can be based on std::map<unsigned long, std::shared_ptr<T>>
). Provide functions to:
shared_ptr
corresponding to a particular unsigned long(The last two functions can be combined).
This has the attraction of not needing to do any dodgy casts between pointers and unsigned long, and also (if the return value is based on an incrementing counter which you test for uniqueness), makes it much easier to find problems where one object is created, deleted, and then another object created at the same address.
This is a sketch of the idea: (Note in particular, it is not thread safe!)
template typename<T>
class Store
{
static std::map<unsigned long, std::shared_ptr<T>> store;
unsigned long h;
bool contains(unsigned long i)
{
return store.find(i) != store.end();
}
public:
unsigned long save(const std::shared_ptr& ptr)
{
if (store.size() >= std::numeric_limits<unsigned long>::max())
{
// Handle error. Only possible if 64 bit program with
// 32 bit unsigned long.
}
// find an unused handle.
do
{
++h;
}
while(contains(h)); // Not a good approach if there are main long-lived objects, and h might wrap.
// Store and return handle.
store[h] = ptr;
return h;
}
std::shared_ptr<T> retrieve(unsigned long handle)
{
if (!contains(handle))
{
// handle error
}
const auto result = store[handle];
store.erase(handle);
return result;
}
};
Upvotes: 9
Reputation: 118435
You have two basic options. Both options assume that on your platform, an unsigned long
is big enough to hold a pointer:
Convert a pointer to your std::shared_ptr
to unsigned long
, and pass it.
Use get()
to retrieve the underlying pointer, and just pass it.
For the second option, it is assumed that your callback does not need to construct another shared_ptr
; otherwise you'll need to use enable_shared_from_this
.
Additionally, both options assume that the shared_ptr
, and the underlying object, will remain in scope when the callback gets invoked. If not:
shared_ptr
using new
. You will need to delete
it after it is no longer needed, and the callback is no longer used.If, on your platform, an unsigned long
is not big enough to accomodate a pointer, it gets clumsier. The cleanest solution would be to keep a std::map<unsigned long, std::shared_ptr<...>>
around, and a counter that assignes a unique unsigned long
value to each shared_ptr
, insert the shared_ptr
into the map, and pass the map's key to the callback.
Upvotes: 1
Reputation: 5370
Sadly there is no "goto" solution for this issue. I had this a few times and worked around this differently depending on the situation.
An "easy" solution would be (if you have some class there) to store the pointers in a container as class member and so make sure they are being kept alive. Then work with raw-pointer inside the functions. You have to make sure though that your callbacks will not get called when your object is destroyed (so store the callbacks with the objects). This only works smoothly though if you don't remove any object from the container. Adding is fine.
With threads you pass the shared ptr by reference and then copy it
{
auto sP = make_shared<...>(...);
thread_start(&sp);
wait_for_thread_init();
}
void thread_start(std::shared_ptr<...>* ref )
//or unsigned long but you can cast this to a shared_ptr<...>* later.
{
std::shared_ptr otherPointer = *ref; //here your ref count gets increased
send_init_complete();
//never use ref from here on. only otherPointer.
}
But C++11 has an own thread library which deals with this better, so you should use this when you use threads.
Depending on your environment you have to get creative here. And in the end when you have no practical solution you need to work with raw pointers. Just add enough to make commentary that the callbacks should delete those objects etc.
Upvotes: 1