Boost logo

Boost :

From: Howard Hinnant (hinnant_at_[hidden])
Date: 2002-03-12 17:39:58


On Tuesday, March 12, 2002, at 04:04 PM, brangdon_at_[hidden]
wrote:

> In-Reply-To: <F2A65FA5-3548-11D6-AF90-003065D18932_at_[hidden]>
> On Mon, 11 Mar 2002 18:37:27 -0500 Howard Hinnant (hinnant_at_[hidden])
> wrote:
>> And of course ~Base() and ~Derived() would tell their respective
>> listeners that they were being destructed. For example:
>
> Suppose these lists of listeners are stored in something like a
> std::vector - in some container which owns memory and cannot have a
> no-throw copy. So the list must be moved or transferred when Base is
> moved
> or transferred. (Even if Base does not use a vector, Derived probably
> shouldn't rely on the fact.)

struct Base
{
     Base(relocate from x)
         listners_(relocate from x.listners_)
     {
         notify_destruction(&x);
         notify_construction();
     }

     Base(move from x)
     {
         x.notify_destruction();
         listners_ = move from x.listners_;
         notify_construction();
     }

     std::vector<listner*> listners_;
};

I'm not really seeing too much of an issue either way. I think I may be
missing your point.

>> Non-destructive move is tons simpler than this.
>>
>> Derived(move from x)
>> : Base(move from x), client_(x.client_), owns_(x.owns_)
>> {
>> notify_construction();
>> x.owns_ = 0;
>> }
>
> But what happens when the source is eventually destroyed? The destructor
> will call notify_destruction(), and this routine will find an empty,
> resourceless list. The notification will be lost. Listeners will see 2
> constructions but only 1 destruction. Chaos reigns.

Nope. ~Dervied() sees a non-null client_ (assuming it was non-null
before the move). Note that the move constructor non-destructively
copied client_ (just a pointer in this example). Then it destructively
copied the owns_ pointer, zeroing the source explicitly. So:

~Dervied()
{
      notify_destruction(); // client_->remove(this)
      delete owns_; // unnecessary because owns_ is null
}

I don't see chaos, as long as this resource-less state is a valid state
for Dervied. The client_ listener will see the addition of the new
Derived, and will retain both Derived on its list until one of them is
destructed. The source may not be destructed immediately. Indeed, it
could be the target of another move assign (as in swap).

> Although I share your unease, I don't think it is a killer argument
> against relocation.

I'm not seeing any killer arguments against relocate either. But the
complications (like being careful with lame ducks, and with auto
objects) are enough that it is a tougher sale.

-Howard


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