Boost logo

Boost :

From: Howard Hinnant (hinnant_at_[hidden])
Date: 2002-02-07 15:00:57


On Thursday, February 7, 2002, at 10:40 AM, Rainer Deyke wrote:

> ----- Original Message -----
> From: "Howard Hinnant" <hinnant_at_[hidden]>
> To: <boost_at_[hidden]>
> Sent: Wednesday, February 06, 2002 5:42 PM
> Subject: Re: [boost] move semantics
>
>
>> template <class T>
>> void
>> swap(T& a, T& b)
>> {
>> T tmp(move(a)); // move construct
>> a = move(b); // move assign
>> b = move(tmp); // move assign
>> }
>>
>> None of these was intended to be a relocation, though the last move
> from
>> tmp certainly could be since the next (implied) statement is the
>> destruction of tmp.
>
> The swap above is potentially less effecient than a relacating swap.
> It also fails entirely on classes that can only support relocation but
> not move:
>
> class C {
> public:
> C() : fp(fopen("myfile", "rb") { if (!fp) throw something; }
> ~() { fclose(fp); }
> private:
> FILE *fp;
> };
>
> It is not always practical for classes to define a null state with no
> resources allocated.

I've been thinking a lot more about this example over the past day. I
think this case may be much more prevalent than I originally thought.
For example, many implementations of std::list and the std::associative
containers fall into this category (not Metrowerks though). These
containers allocate an "end node" on default construction. You are
right. These types of classes can never provide a nothrow move
constructor. They can provide the other 3 forms of move though:
relocate construct, relocate assign, and move assign.

As we've already explored, the optimum for vector::insert is to make use
of move construct and move assign. I believe that vector::insert could
work with any of the following combination of tools:

1. move construct, move assign
2. relocate construct, move assign
3. copy construct, move assign
4. copy construct, copy assign

These are ordered approximately by efficiency, but I have not done a
thorough study. And I suspect that the order of 2, 3 and 4 may vary
with class.

Similar situation with swap as you have pointed out.

Up till now I had been thinking that vector (and swap) would simply
choose between two algorithms (1 or 4). Either you can move or you
can't. But certainly another valid approach would be to subdivide up
the question "can you move" into: Can you move? Can you relocate?

I would still hope that these questions could be answered automatically
without requiring Joe Programmer to register his class for each
capability. And it would be nice if a class that can move could
automatically be made to relocate so that there is not so much to
manually implement for MyClass (I believe Hamish's proposed code does
this).

And clients of "move" (such as vector) would be under no obligation to
ask all of these questions and pick the very optimum. Indeed, they can
simply stick with copy semantics if they want. Or they could settle on
one of move or relocate.

And if we go down this path, perhaps "move" is too ambiguous a word.
What about transfer and relocate? (transfer as in: transfer all
resources to the destination). Or for that matter transfer and move is
another possibility.

I think I'm in favor of supporting both forms of move independently as
long as the burden on those implementing move semantics in their class
does not get too heavy, and as long as the move client syntax does not
get too nasty. At this point I'm not sure of either of these points.
Needs more thinking time... ;-)

-Howard


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