|
Boost : |
From: Howard Hinnant (hinnant_at_[hidden])
Date: 2002-03-09 18:04:07
On Saturday, March 9, 2002, at 02:38 PM, brangdon_at_[hidden]
wrote:
> Is this getting too complicated?
Yup.
Where I'm at:
I see no motivation to pursue a relocate (destructive) assign. A
non-destructive assign will never increase the total number of
resources. I know of no types of objects for which a non-destructive
assign is not implementable (worst case scenario is a swap).
That leaves:
move construct (source remains constructed)
relocate construct (source destructed)
move assign (source remains constructed)
The first two are the problem children:
move construct is not implementable for those classes that do not have a
valid resource-less state.
relocate construct is not implementable for those classes that have a
base class or member classes that do not support move construct (in
order to preserve proper order of construction/destruction of base and
member objects). Another issue with relocate construct is that you can
only do this with a heap object as the source. That's not a killer
argument, but it does mean you have to be very careful. Essentially
relocate construct must be handled with the same care as an explicit
destructor call.
I'm convinced that move semantics can not be accomplished without at
least some language changes. There are two language changes that I see
as key:
1. There must be a way to overload a function in such a way as to
distinguish between a non-const lvalue, a const lvalue and a non-const
rvalue as parameters.
class A {};
A a;
const A ca;
// must be able to overload foo for at least these 3 different calls
foo(a);
foo(ca);
foo(A());
The foo taking a non-const lvalue can modify the argument, but knows
that the outside world will see the modifications.
The foo taking the const lvalue can not modify the argument.
The foo taking the rvalue knows that it can modify the argument, and
that the outside world will never know (it can pilfer the argument).
The first two overloads are our present day foo(A&) and foo(const A&).
2. There must be some way to cast an lvalue to an rvalue without making
a copy, in order to call the rvalue overload:
foo((pretend I'm a rvalue)a); // calls the foo(A()) overload
3. Ok, I know I said 2, this one is optional. It would be nice if
there was compiler support for automatically detecting if a class had
members such as constructor, assignment, maybe destructor? taking a
rvalue type parameter/overload. These would be the move signatures for
a class. We could have the class register with a traits class, but that
is clumsy and error prone.
4. It would be nice if the compiler took advantage of move semantics
(when available) to aid in return value optimization.
5. It would be nice to have a traits class that identifies objects with
trivial move semantics (can be moved with memcpy). Given this, a
std::move(first, last, to) function could be created much like the
present day std::copy (maybe have variations for
construct/assign/destructive).
Footnote: The language overload/rvalue/reference part of the solution
to move semantics appears to also help the "function forwarding" problem
if the language rules are set up just so. Solving more than one problem
with a language change is a very Good Thing.
-Howard
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk