fish2000
fish2000

Reputation: 4435

Smart pointer analog of `std::shared_ptr` with API to bind callbacks to refcount-modifying events e.g. release/retain … is this a thing?

I am in need of a smart-pointer structure – analogous to std::shared_ptr – that offers me some kind of API with exposed hooks, to which callbacks to refcount-modifying events (like e.g. release/retain, aka refcout increment/decrement) can be bound.

I either want to implement this myself, or use something off-the-shelf, should it exist.

Like, I would like to optimally be able to say “Invoke this callable whenever you increment the refcount [but that one when decremementing]” while defining this putative shared_ptr-ish smart pointer (much as delete-expressions and deleter functors are used, respectively, in shared_ptr and unique_ptr definitions).


EDIT (from my comment below) – Here’s why I want this: I currently have an Image class template that, at its heart, has a std::shared_ptr holding a (potentially large) contiguous heap-allocated memory block. Image has inner classes implementing hyperslab iterators (exposing e.g. color planes, CBIR hash data, &c) that use std::weak_ptr to refer back to the memory block of the owning Image instance. I want to extend Image for specific refcounted runtimes – for example the Python c-api – and tying into the existing std::shared_ptr refcounter apparatus is preferable to keeping two disparate systems in sync.

Upvotes: 5

Views: 1374

Answers (1)

hkBst
hkBst

Reputation: 3360

The default implementation of shared_ptr has shared_ptr's that are sharing an object all pointing to a so-called control block. It is this control block that holds the reference counters and is thus the object that more naturally can react to reference count changes.

But if you really want to do it via a smart pointer the following might work:

using std::shared_ptr;

template<class T> class sharedX_ptr;

// the type of function to call when a refcount change happens
template<class T>
void inc_callback(const sharedX_ptr<T>& p)
{
  std::cout << "Increasing refcount via " << &p
            << ", for object: " << p.get() << ", use_count: " << p.use_count()
            << std::endl;
}

template<class T>
void dec_callback(const sharedX_ptr<T>& p)
{
  std::cout << "About to decrease refcount via " << &p
            << ", for object: " << p.get() << ", use_count: " << p.use_count()
            << std::endl;
}

template<class T>
class sharedX_ptr : public shared_ptr<T>
{
  typedef void (*callback)(const sharedX_ptr<T>&);
  callback inc, dec;
public:
  typedef shared_ptr<T> base;

  sharedX_ptr(const sharedX_ptr& p) : base(p), inc(p.inc), dec(p.dec)
  { if (this->get()) inc(*this); }

  template<class U>
  sharedX_ptr(sharedX_ptr<U>&& p) : base(std::move(p)), inc(p.inc), dec(p.dec)
  { /*if (this->get()) inc(*this);*/ }

  template<class U>
  sharedX_ptr(shared_ptr<U> p, callback i = inc_callback<T>, callback d = dec_callback<T>)
    : shared_ptr<T>(std::move(p)), inc(i), dec(d)
    { if (this->get()) inc(*this); }

  sharedX_ptr& operator=(sharedX_ptr&& p) {
    if (this != &p) {
      if (this->get()) dec(*this);
      base::operator=(std::move(p)); inc = p.inc; dec = p.dec;
      /* if (this->get()) inc(*this); */
    }
    return *this;
  }

  template<class U>
  sharedX_ptr& operator=(const sharedX_ptr& p) {
    if (this != &p) {
      if (this->get()) dec(*this);
      base::operator=(p); inc = p.inc; dec = p.dec;
      if (this->get()) inc(*this);
    }
    return *this;
  }

  void reset() { if (this->get()) dec(*this); shared_ptr<T>::reset();}

  ~sharedX_ptr() { if (this->get()) dec(*this); }
};

Upvotes: 2

Related Questions