Boost logo

Boost :

From: Howard Hinnant (hinnant_at_[hidden])
Date: 2002-03-10 13:50:36


On Sunday, March 10, 2002, at 12:36 PM, brangdon_at_[hidden]
wrote:

>> 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).
>
> OK, this is new to me.
>
> How does move help with the order of construction/destruction here? What
> is "proper order", anyway? At first sight, either construction order or
> reverse construction order are equally applicable. Either can be wrong.

As you know, in present day C++ base (and virtual base) classes are
constructed first, then members are constructed in the order that they
appear in the declaration. Destruction occurs in the reverse order.

Although it might be possible to make an exception on the order of
destruction of members during a relocate construct, I don't even see
that possibility for base classes. Consider:

struct Base {};

struct Derived
        : Base
{};

Also consider the possibility that Base is designed to be derived from
by client code. Thus the author of Derived probably has to respect some
encapsulation of Base. For Derived to relocate construct it must first
ask Base to relocate construct. After this happens Derived can now
relocate construct its members. And finally the entire object is
destructed.

Note that the base class got destructed first. During the period that
Derived was busy relocating its members, it was operating with a
destructed Base. This is a rather bizarre configuration. What happens
if Derived needs to ask Base a question? During an ordinary ~Derived()
there is an arbitrarily rich communication between Derived and Base
because Base hasn't been destructed yet.

In a nutshell, I find changing the order of destruction of base classes
too scary. Therefore I believe that Derived will have to ask Base to
move construct itself, leaving behind a valid Base that Derived can
communicate with during its own destruction, after which ~Base() would
run.

And the more I thought about this, it occurred to me that changing the
order of destruction of member objects (from that done in the ordinary
destructor) is pretty scary too.

>> 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.
>
> Is this another approach to working with temporaries? I had thought the
> issue would be addressed more directly by turning temporaries into
> lvalues
> and allowing them to bind to non-const references (with implicit
> conversions disallowed).

Yes this is another approach. The idea is have a new kind of reference
that allows temporaries to bind to them, even prefers temporaries in the
presence of overloading. It is all still extremely preliminary. It
could help in cases like operator+() for a string class (syntax pulled
out of thin air):

string operator+(const string& x, const string& y) {return string(x) +=
y;}
string operator+(temporary string x, const string& y) {return x +=
y;}
string operator+(const string& x, temporary string y) {return y +=
x;}
string operator+(temporary string x, temporary string y) {return x +=
y;}
...
string s = s1 + s2 + s3 + s4;

The versions taking a temporary know that they can pilfer that argument
with impunity. There is no need to copy construct one of the
arguments. You can just add to the temporary and return it. With
sufficient rvo (possibly aided by move semantics), unnecessary
temporaries could be a thing of the past.

> This (and typeof) are the two most important
> language changes I hope for.

Agreed that both of these are very important. I personally consider the
introduction of a C99 compatible long long as the only language change
more important than these two (but not nearly so difficult nor
controversial ... I hope!).

-Howard


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