Boost logo

Boost :

From: David Abrahams (dave_at_[hidden])
Date: 2003-01-30 00:33:54


"Andrei Alexandrescu" <andrewalex_at_[hidden]> writes:

> "David Abrahams" <dave_at_[hidden]> wrote in message
> news:uadhj9vne.fsf_at_boost-consulting.com...
> [snip]

Might help to know what you're responding to here, though I can try to
guess...

> One problem I see is that the constructor uses a different syntax
> than any other function. Imho syntax uniformity is good, and lack
> thereof is not good.

In general I agree, though it's not clear how that relates to our
problem.

> Other languages get away from this problem by considering the first
> assignment to an base or member, the constructor call for that base or
> member. If no first assignment is statically decided, there is a
> compile-time error.
>
> If that were the case, Loki::SmartPtr's constructor could be written like
> this:
>
> SmartPtr::SmartPtr(T* p)
> {
> *this = storage(p);
> ScopeGuard g = MakeGuard(storage::destroy, p);
> *this = ownership(p);
> g.Dismiss();
> *this = conversion();
> *this = checking();
> }

Conceivably workable for C++, though very expensive in copies using
that precise form. It would require different unwind sequences for
each differently-ordered constructor. I'm not sure whether it's worth
breaking the invariant about members being destroyed in the reverse
order they constructed in, though I suppose it's possible to eliminate
all of that by restricting the initialization order to match the order
of bases and members.

> Well, dream mode off. If that's not to work, using Dave Abrahams' idea of
> passing a default argument might apply, however the problem is that you
> can't pass previous arguments to the default argument :o/.

Sure, you can just use a base implementation layer. Then you don't even
need a default:

template <class T, class P1, class P2, class P3>
struct pb_impl : P1, P2, P3
{
   pb_impl(T* x, deleter<T> del)
      : P1(x), P2(x), P3(x)
   {
       del.release();
   }
};

template <class T, class P1, class P2, class P3>
struct policy_based
  : pb_impl<P1,P2,P3>
{
    policy_based(T* x)
       : pb_impl(x, deleter<T>(x))
       {}
};

Note how this very quickly turns back towards a kind of "pure RAII."

> I suggest we just make an explicit function acquire() for the ownership
> policy and have all of its other member functions assume acquire() was
> called.

It's not obvious to me what that looks like, but if you think you've
got an acceptable answer maybe that doesn't matter.

-- 
                       David Abrahams
   dave_at_[hidden] * http://www.boost-consulting.com
Boost support, enhancements, training, and commercial distribution

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk