On Mon, 2015-08-17 at 10:38 -0400, Andrew Stitcher wrote:
> I like the way you're thinking - I expect to have real time to look 
> at
> your code Tomorrow/Wednesday.
> 
> One point that occurred to me over the weekend (that I think is
> probably incorporated in what you've done here). Is that C++ code 
> never
> needs to use a shared_ptr to any Proton struct because Proton ref
> counts by itself. In other words the C++ ref count could only ever by 
> 0
> or 1. All the C++ code ever needs is a unique_ptr. I suspect this 
> point
> doesn't really affect your proposal here though.
> 
> Andrew
> 

Here's a preview of what I'm thinking now, it follows from the code I
published

/**
   The C++ proton binding can be used in a memory-safe way via
std::shared_ptr,
   std::unique_ptr, boost::shared_ptr and boost::intrusive_ptr. If you
are using
   an older C++ compiler and cannot use boost, you can can optionally
use
   proton::pn_shared_ptr to automate memory management.

   You can also use the binding in an *unsafe* C-like way with plain
pointers if
   you must avoid the (low) overhead of reference counting, or if you
are writing
   mixed C/C++ code. Caveat emptor.
*/

template <class T> class pn_shared_ptr;
template <class T> class pn_borrowed_ptr;

/** Base class for pn_ smart pointers, see pn_shared_ptr and
pn_borrowed_ptr */
template <class T> class pn_base_ptr {
  public:
    typedef typename T::pn_type pn_type;

    T* get() const { return ptr_; }
    operator T*() const { return ptr_; }
    T* operator->() const { return ptr_; }

    // get_pn is only needed if you are mixing C and C++ proton code.
    pn_type* get_pn() const { return reinterpret_get_pn<P*>(ptr_); }

#if PN_USE_CPP11
    operator std::shared_ptr<T>() const { return
std::shared_ptr<T>(incref(), pn_object_decref); }
    operator std::unique_ptr<T>() const { return
std::unique_ptr<T>(incref(), pn_object_decref); }
#endif
#if PN_USE_BOOST
    operator boost::shared_ptr<T>() const { return
boost::shared_ptr<T>(incref(), pn_object_decref); }
    operator boost::intrusive_ptr<T>() const { TODO; }
#endif

    // FIXME aconway 2015-08-17: get_pning conversions to compatible
pointers

  private:
    pn_base_ptr(T* p) : ptr_(p) {}

    T* incref() { pn_object_incref(get_pn()); return ptr_; }
    void decref() { pn_object_decref(get_pn()); }

    T* ptr_;

    template <> friend class pn_shared_ptr<T>;
    template <> friend class pn_borrowed_ptr<T>;
};

/**
   pn_shared_ptr is a smart pointer template that uses proton's
internal
   reference counting. Proton objects hold their own reference count so
there is
   no separate "counter" object allocated. The memory footprint is the
same as a
   plain pointer.

   It is provided as a convenience for programmers that have pre-c++11
compilers
   and cannot use the boost libraries. If you have access to
std::shared_ptr,
   std::unique_ptr, boost::shared_ptr or boost::intrusive_ptr you can
use them
   instead. pn_shared_ptr converts automatically with correct reference
   counting.
*/
template <class T> class pn_shared_ptr : public pn_base_ptr<T> {
  public:
    pn_shared_ptr(pn_shared_ptr p) : ptr_(p) { incref(); }
    pn_shared_ptr(pn_borrowed_ptr p) : ptr_(p) { incref(); }
    ~pn_shared_ptr() { decref(); }

  private:
    pn_shared_ptr(T* p) : pn_base_ptr<T>(p) {}
    template <> friend class pn_shared_ptr<T>;
};

/**
   pn_borrowed_ptr<> is used as a return and parameter type in
proton::functions
   to automate correct memory management. You do not normally need to
use it in
   your own code.

   It behaves like (and converts to/from) a plain pointer, the only
difference
   from a plain pointer is that converting it to any "owning" smart
pointer type
   will automatically add a reference. Converting from (i.e.
"borrowing") a plain
   or smart pointer will not change the reference couint.
*/
template <class T> class pn_borrowed_ptr : public pn_base_ptr<T> {
  public:
    typedef typename pn_base_ptr<T>::pn_type pn_type;

    /** This constructor is only needed if you are mixing C and C++
proton code */
    explict pn_borrowed_ptr(pn_type* p) :
pn_base_ptr(dynamic_cast<T*>(p)) {}
    pn_borrowed_ptr(T* p) : pn_base_ptr<T>(p) {}
    operator T*() const { return ptr_; }
    operator pn_shared_ptr<T>() const { return
pn_shared_ptr<T>(incref()); }
};

Reply via email to