Boost logo

Boost :

From: Ion Gaztañaga (igaztanaga_at_[hidden])
Date: 2007-04-16 13:33:23


Howard Hinnant wrote:
>
> [snip]
>
> There is nothing in the rvalue ref proposals that really nails this
> down. It is up to each class to define its behavior after a move.
> At the very least it should support assignment and destruction in
> order to work with generic code. Beyond that I'd say the class
> should be free to implement whatever semantics / interface it feels
> best.

I respectfully disagree ;-) If the object is still there and can be used
it should be usable. If we had destructive move-semantics, I would agree
that the state of the objects should be undefined (or even better,
destroyed), but in that case I would expect compiler help to detect uses
of move-destructed variables after the move-destruction.

std::vector<T> myvect(...);
//myvect's destructor is called, the object is not longer usable
std::vector<T> myvect2(std::destructive_move(myvect));
myvect.resize(1000); <-- COMPILATION ERROR

In my opinion, the standard should clearly say what happens with an
standard component. An example: what's the state of an STL container
after being moved?

std::vector<T> myvect(...);
std::vector<T> myvect2(std::move(myvect));
myvect.resize(1000); <-- is this correct?

If myvect is allowed to be in a non-usable state, the allocator might be
moved from myvect to myvect2. If myvect should be usable, the allocator
should be copied --> corollary: If we want non-throwing move
constructors and assignments (which is surely required for objects we
want to place in STL containers, like std::list<std::vector<T> >)
allocator copying shouldn't throw.

If the standard does not specify anything, implementors of allocators
must always support the worst case (copying shouldn't throw) but they
can't use the advantages (the vector is NOT reusable). Users also get
the worst of both worlds.

Since current move semantics are non-destructive the state of the object
should be usable. For objects that have a default-constructor (like
shared_ptr or vector) the moved state could be equal to
default-constructed (which is consistent *and* usable). And no-throw
guarantee should be required for such move operations

This might complicate a bit the implementation of allocators, but it's
perfectly possible to achieve this with containers. For shared_ptr, I
don't know if the state should be default-constructed, but I would like
to reuse that object via reset().

For objects that have no such default-state, and have no resource
reassignment functions (like reset() or similar) there is no problem
because there is no interface to reuse the object. For objects that
don't have default-constructor but have resource reassignment functions,
the state might be undefined, but I would require object reuse
capability. In any case, you need to internally maintain the "moved"
state so that the destructor does not crash the program. Since we have
to pay some price (the zombie state, if you want to call it), let's take
something in return.

My 2 cents,

Ion


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