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.

I'll do you one better - C++ can use *either* (or boost
shared/intrusive pointers) seamlessly if we say that all C++ smart
pointers own a *proton reference*, not a *proton object*.

Will have another proposal out shortly to clarify.

> 
> On Sat, 2015-08-15 at 06:09 -0400, aconway wrote:
> > In case you spotted the bug in the previous proposal here is a much
> > better one. This one doesn't have code yet but you can imagine how 
> > it
> > would work based on the previous code. I'll post updated code 
> > shortly.
> > 
> > Updated proposal to integrate C++ and proton C memory management.
> > 
> > - use refcounting consistently, no pn_free. Fixes bug in the 
> > previous
> > proposal.
> > - added pn_shared_ptr for portable refcounting in C++11 and C++03.
> > - better integration with std:: and boost:: smart pointers in C++11 
> > and
> > C++03.
> > 
> > The idea is that every ::pn_foo_t type has a corresponding C++
> > proton::foo class with member functions so you can do `foo* p=...; 
> > p
> > ->something()` in C++ and it will call `::pn_foo_something()` on 
> > the
> > underlying `::pn_foo_t`.
> > 
> > The first trick: the foo class is *empty and never instantiated*. A
> > foo* returned from the C++ API points directly to the raw C `struct
> > pn_foo_t`. You can reinterpret_cast between the two if you want to 
> > mix
> > C and C++ APIs (you don't really want to.) Doing `foo* p=...; 
> > delete 
> > p`
> > will actually call pn_object_decref(reinterpret_cast<void*>(p)).
> > 
> > The next trick: proton:: functions return 
> > proton::pn_shared_ptr<foo>, 
> > a
> > smart pointer using proton refcounts directly 
> > (pn_object_incref/decref)
> > It is portable and useful as-is in c++03 and c++11, but is not as
> > featureful as the std:: and boost:: smart pointers.
> > 
> > However it can be converted to any of std::unique_ptr, 
> > std::shared_ptr,
> > std::auto_ptr, boost::shared_ptr and boost::intrusive_ptr safely 
> > with
> > correct refcounting. Each unique_ptr, auto_ptr or shared_ptr family
> > owns a proton refcount (not the actual proton object) so it is safe 
> > to
> > have multiple unique/shared_ptr to the same underlying proton 
> > object.
> > 
> > So some examples, given:
> > 
> >     class foo { pn_shared_ptr<foo> create(); ... }
> >     class event { pn_shared_ptr<foo> foo(); }
> >     event e;
> > 
> > This works in C++11:
> > 
> > - std::shared_ptr<foo> p = e.foo(); // shared_ptr refcounts 
> > integrated
> > with proton
> > - std::unique_ptr<foo> p = foo::create();
> > 
> > These are all safe and portable in C++03 or C++11:
> > 
> > - e.foo()->somefunc();                  // call direct, no 
> > refcounting.
> > - pn_shared_ptr<foo> p = e.foo();       // use pn_shared_ptr 
> > directly.
> > - std::auto_ptr<foo> p = foo::create(); // portable but deprecated 
> > in
> > C++11
> > - boost::intrusive_ptr<foo> p = e.foo() // use proton refcount
> > directly.
> > - boost::shared_ptr<foo> p = e.foo()    // boost refcounts 
> > integrated
> > with proton
> > 
> > The following are *unsafe* but legal in all C++ versions:
> > 
> > - foo* p = e.foo();         // unsafe, p may be invalidated by 
> > later
> > proton actions.
> > - foo* p = foo::create();   // unsafe, p will not automatically be
> > freed.
> > 
> > There is almost no overhead compared to using the raw C interface. 
> >  If
> > you use boost|std::shared_ptr it will allocate an internal counter 
> > per
> > pointer *family* (not instance) which is not much overhead, 
> > otherwise
> > there are 0 extra allocations. The the template magic will 
> > evaporate 
> > at
> > compile time.
> > 
> > NOTE: proton::functions will take foo& as a parameter so you can 
> > always
> > pass *p for any pointer type.
> > 
> > On Fri, 2015-08-14 at 20:52 -0400, aconway wrote:
> > > I have a proposal to integrate C++ and proton C memory 
> > > management, 
> > > I
> > > need a sanity check.
> > > 
> > > Attached is an executable C++ sketch and test (pn_ptr.cpp) and a 
> > > script
> > > (test.sh) that runs the combinations of g++/clang++ and 
> > > c++11/c++03, 
> > > as
> > > well as some tests to verify that we get compile errors to 
> > > prevent
> > > mistakes.
> > > 
> > > The idea is that every pn_foo_t type has a corresponding C++ foo 
> > > class
> > > with member functions to make it easy to call pn_foo_* functions 
> > > in 
> > > C++
> > > (converting std::string/char* etc.)
> > > 
> > > The first trick: the foo class is empty and never instantiated. A 
> > > foo*
> > > actually points to the same memory location as the pn_foo_t*. You 
> > > can
> > > reinterpret_cast between the two, and deleting the foo* will 
> > > actually
> > > call pn_foo_free(pn_foo_t*).
> > > 
> > > The next trick: proton::event accessor functions return a 
> > > pn_ptr<foo>,
> > > which is an internal class that users cannot instantiate. What 
> > > they 
> > > can
> > > do is convert it by assignment or construction to any of: foo*,
> > > std::auto_ptr<foo>, std::unique_ptr<foo> or std::shared_ptr<foo>. 
> > > In
> > > the shared_ptr case the conversion automatically does a 
> > > pn_incref().
> > > 
> > > The upshot of this is that you can use plain foo* or any of the
> > > std::smart pointers to point to a foo and it Just Works. If you 
> > > don't
> > > use shared_ptr you need to understand the proton C API lifecycle 
> > > rules,
> > > but with shared_ptr it is all fully automatic.
> > > 
> > > Moreover if you don't use shared_ptr there is almost no overhead 
> > > over
> > > using pn_foo_t* directly in the C API, as the compiler should 
> > > optimise
> > > away all the inline template magic.
> > > 
> > > This works with c++11 (everything works) or c++03 (just foo* and
> > > auto_ptr). It will be trivial to add support for 
> > > boost::shared_ptr 
> > > so
> > > nice memory management will work with c++03 and boost.

Reply via email to