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()); } };