Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass std::shared_ptr to callback through unsigned long?

Tags:

c++

shared-ptr

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.

like image 712
Ragnar Avatar asked Dec 19 '22 12:12

Ragnar


1 Answers

Create a static store (which can be based on std::map<unsigned long, std::shared_ptr<T>>). Provide functions to:

  • register a shared pointer in the store (which saves it in the map, and returns a unique long).
  • retrieve the shared_ptr corresponding to a particular unsigned long
  • remove 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;
    }
 };
like image 78
Martin Bonner supports Monica Avatar answered Dec 21 '22 01:12

Martin Bonner supports Monica