Boost logo

Boost :

From: Ion Gaztañaga (igaztanaga_at_[hidden])
Date: 2007-04-17 12:13:47


Peter Dimov wrote:
> Joe Gottman wrote:
>
>> There are many more ways to reuse an object than assignment and
>> reset. For instance, I would be extremely disappointed if the
>> following code didn't work:
>>
>> vector<double> foo;
>> vector<double> bar = move(foo);
>> foo.resize(10);
>> for (size_t n = 0; n < 10; ++n) {
>> foo[n] = n + 7;
>> }
>
> The code will work under any implementation of the move constructor, IMO.

Well, some argue that only a move assignment or destructor should work
after an object is being moved. I think the container should continue to
work. I would be really disappointed if Joe's code does not work.

> The more interesing question is, given:
> bar = move(foo);
>
> would you be extremely disappointed if foo doesn't retain its allocator
> instance but gets bar's after the move?

If you want to left bar usable there is no other chance than swapping
allocators.

I would like to differentiate two cases with containers:

Move assignment:

  It can easily implemented in terms of swap. Allocators are also
swapped if they are not equal (or just swapped without any question).
Allocators must go with the moved values.

Move constructor:

  This is really tricky. If we want to left the moved object usable, we
need to copy the allocator. Something like:

Container(Container &&moved_container)
    : allocator_(moved_container_.allocator_) //Note, copy constructed
{
    //Default initialization
    // ....

    //and now swap
    this->swap(moved_container);
}

Metrowerks/Freescale implementation implemented something like this, so
moved containers were left perfectly usable. Since in Interprocess I
wanted to maintain containers usable after being moved I've chosen the
same option. The problem is that the allocator must be copy constructed
and then swapped. This means that if we want a no-throw move
constructor, allocator copying can't throw.

In practice, I haven't seen an allocator (stateless or stateful= with a
throwing copy-constructor, even shared memory ones. And if they need to
acquire resources, they could delay the exception launch until the
allocation function.

The dynamic allocation of the "end" node in some containers (some
implementation just embed them in the container so there is no problem)
might also throw. But nothing that can't be delayed until an insertion
is requested. The standard might easily mandate non-throwing copy
constructors for allocators without breaking code and limiting current
allocators.

To sum up: Leaving the moved container fully usable and having no-throw
guarantee for move constructors needs some tweaks, but in practice I
think it's perfectly achievable and offers big advantages.

Regards,

Ion


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