|
Boost : |
From: brangdon_at_[hidden]
Date: 2002-03-10 12:36:18
In-Reply-To: <009201c1c7be$05f2dac0$0500a8c0_at_[hidden]>
On Sat, 9 Mar 2002 17:54:34 -0500 David Abrahams (david.abrahams_at_[hidden])
wrote:
> > I know you dislike vector::insert written in terms of relocate,
> > because it has to undo the move if a copy fails.
>
> Actually, this is debatable. You could instead destroy all or part of
> the vector elements, so long as you leave only a (possibly empty)
> contiguous region of constructed elements.
Yes, several ways of dealing with the exception had been listed earlier in
the thread. I prefer the way which gives insert the strong guarantee.
Either all items are inserted (and no exception was thrown), or no items
are inserted. Then any partial insert has to be undone.
Normally for vector::insert to give the strong guarantee, it would have to
do a lot of extra copying even if no exception is thrown. However, using
the no-throw guarantee of transfer/move, we can provide the strong
guarantee for insert without extra copying in the common case.
I think this is a good deal. In fact I think that any time the user
provides a stronger guarantee to the std library, the std library should
reciprocate by providing a stronger one back, if possible. Usually the
exchange is no-throw => strong.
Doesn't this sound like a reasonable and fair guideline? Any std routine
which relies on the no-throw guarantee from user code, should provide at
least the strong guarantee back. It may mean more work for std
implementors, but in a way it simplifies the design process by eliminating
some options.
I hope you agree to this whatever we decide on the move versus transfer
issue. Then the move/transfer choice should be evaluated on the basis that
code which uses them provides the strong guarantee.
[I have re-ordered these quotes slightly for clarity.]
> > Is move construct ever useful for code that gives the strong
> > guarantee?
> It was my impression that the difference between move and relocate is
> that relocate leaves the source object destroyed whereas move does not.
> I don't see how this could possibly change the available exception
> guarantees, since you can always build relocate semantics (albeit
> expensively) from move + destroy-source.
Sorry, that should have been "more useful" rather than just "useful".
Here's my reasoning.
It seems to me that if you want to provide the strong guarantee, you never
want to leave surplus objects which are "empty" (ie, without resources,
and hence not in the state the user eventually wants/expects), but which
still need destruction. So for example a version of vector::insert which
provides the strong guarantee in terms of move, will need some extra code
to go back and destroy the empty source objects which move leaves behind.
Once this code is accounted for, the "move" version is no longer smaller
and tighter than the "transfer" version. In fact it will be bigger and
slower.
So yes, although both are "useful", transfer is "more useful". It makes
the implementation of vector insert simpler. It does more of the necessary
work. I don't see why one would ever prefer move over transfer when
implementing things like vector::insert.
> > The relocate version supports a wider range of classes.
>
> I don't see how. If you can move, you can relocate. I think the converse
> may be true, but I'm not sure of it.
The converse isn't true. There are classes which can support relocate, but
which cannot support move. A routine which which relocates its arguments
can work with such classes, but one which moves them cannot. That is why I
said the relocate() version is more general. It supports more classes.
At least from this point of view. Howard Hinnant makes a good point about
not being able to switch off destruction for stack objects. Hence objects
on the stack can only be moved, not relocated. At least, not without
language changes.
Classes which can support locate but not move fall into (at least) two
groups. The first are ones whose class invariant does not permit a
resource-free empty state. The second group are the immutable classes, or
those with const members, which do not even support assignment. The second
group is not relevant to std::vector, but might be important elsewhere.
-- Dave Harris
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk