Boost logo

Boost :

Subject: Re: [boost] [move][container] Review Request (new versions of Boost.Move and Boost.Container in sandbox and vault)
From: Howard Hinnant (howard.hinnant_at_[hidden])
Date: 2009-10-17 13:49:36


On Oct 17, 2009, at 12:26 PM, Thomas Klimpel wrote:

> Howard Hinnant wrote:
>> So why do it? What's the benefit even if the cost is small?
>>
>> Consider std::remove: This is one of the few algorithms in
>> <algorithm> which is not a "resource preserving" permutation.
>> Consider remove({a, b, c, d, e}, c). This will result in the
>> sequence
>> {a, b, d, e, e'}. To achieve this result, the following move
>> assignments will take place:
>>
>> c = move(d);
>> d = move(e);
>>
>> The first move assignment is not into a resource-less c. If move
>> assignment into c doesn't "clear", when do those resources go away?
>> For most resources (such as memory), it doesn't really matter when.
>> The resources will still be owned if move-assignment doesn't
>> aggressively destroy them (probably by e').
>>
>> But for some resources (threads, file handles, mutexes), it will
>> matter if they live too long. The client calling std::remove may or
>> may not destruct e' "soon". But the client asked std::remove to
>> remove c (and presumably all of c's resources). I do not think it
>> would be a good idea for std::remove to also say: Oh, and you better
>> destruct e' too just to make sure c is really gone.
>
> I was initially looking for an example of this sort to "prove" that
> "clear" is required, but came to realize that I probably won't find
> one. (The examples Dave gave me are sufficient to "prove" that
> "clear" is required, but they are related to subtleties of the C++
> language and not inherent in moving itself.)
>
> But why do I think that this example doesn't "prove" that "clear" is
> required? Consider "remove({a, b, c, d, c}, c)" instead of "remove
> ({a, b, c, d, e}, c)". This will result in the sequence {a, b, d,
> d', c}. So the assumption that the client asked std::remove to
> remove c (and presumably all of c's resources) is simply not true.
> The client really has to destruct the elements of the tail range to
> ensure that c is really gone, even if the move-assignment operator
> calls "clear".

That's a good counter example. I should've prefaced my example with
something like: The client has already unique'd his sequence and knows
that the desired removed element is not at the end of the sequence.

I also made another mistake in my last post: unique is not a
"resource preserving" permutation.

>> This is the benefit of move assignment "clearing" potentially
>> significant resources aggressively. I believe this benefit outweighs
>> the cost.
>
> My current understanding is that there are more subtle reasons why
> move assignment should "clear" potentially significant resources
> aggressively.
>
>
> There is still the open point whether self-move-assignment should be
> forbidden. I wrote in another mail: "On the other hand, as long as
> the absence of conclusive counter examples can't be "proved", ruling
> that move-assignment may generally be implemented as swap will be
> risky or worse." I think the same should apply to self-move-
> assignment: As long as it can't be proved that forbidding self-move-
> assignment does no harm, ruling that self-move-assignment is
> forbidden will be risky or worse.

When move assigning into a resource-less lhs, self move assignment
appears to me to be harmless.

Note that I do not advocate that move-assignment be generally
implemented as swap.

I generally advise that move assignment be implemented as:

1. Destroy non-memory resources.
2. Move assign base classes.
3. Move assign data members.
4. Fix up invariants.

When 1 and 4 are no-ops, it should be safe to let the compiler default
this for you.

-Howard


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