
On 08/31/2006 03:07 PM, Paul Mensonides wrote:
-----Original Message----- [snip]
smart pointer so that it doesn't require a double allocation.)
I assume you mean one which doesn't use an intrusive refcount, IOW, uses a "detached" refcount like the existing shared_ptr? IOW, with the current shared_ptr, an one allocation is for the pointed-to object, the other is for the refcount.
Yes, basically you have the smart pointer allocate the pointed-to-object itself as a data member of a struct that also contains the reference count. E.g.
template<class T> class smart_ptr { // ... private: struct data { unsigned long rc; T value; } * p_; smart_ptr(data* p); };
You need a forwarding contructor on the 'data' structure to directly initialize the 'value' member. You also need a forwarding function on whatever takes the arguments from clients--so the resulting syntax looks something like:
smart_ptr<X> p = make_ptr<X>(a, b, 123);
The make_ptr<X> function has to construct a 'smart_ptr<X>::data' object and initialize a smart_ptr with it and return that smart_ptr.
The above make_ptr<X> is close to the managed_ptr:: auto_overhead<X,ulong_rc> where: template<class> struct ulong_rc { unsigned long rc; }; and instead of: smart_ptr(data* p) there would only be: smart_ptr(auto_overhead<T,ulong_rc>& a_auto) IOW, auto_overhead is simply derived from auto_ptr with the pointee being an instance of the managed_ptr:: overhead_referent_vals<ulong_rc,T>. IOW, overhead_referent_vals<ulong_rc,T> corresponds to your smart_ptr<T>::data. The reason for the elaborate overhead_referent_* classes is to allow different smart_ptr policies, e.g. to allow strong and weak pointers. The reason for disallowing: smart_ptr(overhead_referent_vals<ulong_rc,T>*) is to never expose a raw pointer to the client.
One problem of forwarding is arity (which can be more-or-less solved with code generation). The more stubborn problem with forwarding is temporaries. They cannot be bound to a non-const reference, and the template mechanism cannot deduce T as const U in a parameter of type T&. OTOH, non-temporaries don't have any problem deducing T as U or const U in a parameter of type T&.
Yeah, I had that problem which is why the a_auto above is not 'const &'. I remember some attempt at a workaround, but can't remember the details or even if it worked.
Unfortunately, the only way to handle it transparently is to overload via cv-qualifier--which leads the the combinatorial explosion when multiple parameters are involved.
:(
the workaround implemented with the help of managed_ptr_ctor_forwarder.hpp:
generates CTOR's of the form:
template < class VecOfTypes
ctor_this_type ( VecOfTypes const& , mpl::at_c<VecOfTypes,0>::type a0 , mpl::at_c<VecOfTypes,1>::type a1 , ... , mpl::at_c<VecOfTypes,n>::type an ) : ctor_base_type ( a0 , a1 , ... , an ) {}
IOW, the client has to specify the "signature" of the ctor_base_type CTOR via a single VecOfTypes template arg to the ctor_this_type CTOR. The justification for this was that the client would have to know which ctor_base_type CTOR he wanted anyway, so it would not be that much of a burden for him to name it, indirectly, by supplying the "signature".
I'm not sure why you need to add this into each class (rather than just to the smart-pointer-related interfaces).
Sorry I was unclear. This above is only needed for the auto_overhead class. IOW, replace ctor_this_type with auto_overhead and ctor_base_type with Referent from auto_overhead<Referent,Overhead>. Of course it's a little more complicated, but that's essentially what's happening with the MANAGED_PTR_CTOR_FORWARDER_OVERLOAD macro invokation in the middle of the auto_overhead class definition.
It may be that we're not talking about the same thing, but the smart_ptr facilities above could be designed without *any* intrusive requirements on the type pointed-to
Likewise, auto_overhead does not have *any* intrusive requirements since the only allocation is for overhead_referent_vals<ulong_rc,pointee_type>.
and without *any* manual listing of argument types by the client. Granted, you can only support a fairly low number of parameters (larger if you ignore volatile).
And this, AFAICT, is the advantage of make_ptr vs. auto_overhead. IOW, auto_overhead does have to supply, as mentioned in my previous post, the signature (VecOfTypes in the above code) of the desired "target" CTOR.