Boost logo

Boost :

From: Andrea Torsello (torsello_at_[hidden])
Date: 2004-04-19 12:06:47


David Abrahams wrote:

>>
>> Oh, OK, if you assume that the compiler can always perform return value
>> optimization, you are right. But I feel there is a difference in
>> requiring the compiler to perform RVO on direct initialization from
>> temporaries and requiring the compiler to perform it every time it is
>> possible.
>
> You appear to be making an argument about what's theoretically going
> to work in correct, portable C++, based on the behavior of a
> particular compiler implementation.
>
> I am not requiring RVO unless you take what EDG accepts in strict mode
> as the defintion of "standards conforming". I do not. EDG is
> erroneous, IMO, in issuing that error, so we either turn off strict
> mode or work around it by allowing its native RVO to work. GCC has a
> much better example of what I consider a correct interpretation of the
> standard in requiring that it be possible to construct a new temporary
> rvalue from an existing one that will be bound to a reference (and
> not "copy construct", as I point out in N1610).

What I was saying is that if you provide a non-explicit X(X const &)
constructor when passing a temporary by value you are performing a copy.
So if you provide a non explicit copy ctor, you are requiring the compiler
to perform RVO or you would have an extra copy. If you can assume the
compiler can peform RVO in all cases why have the move construct at all?
 
>> Using the explicit constructor technique #2 works even with compilers
>> that do not support RVO, as long as you use the assignment constructor
>> instead of the direct copy constructor.
>
> Well, I challenge you to find a compiler that doesn't support at least
> some RVO. But if you did find one, technique #1 is as good as
> technique #2 in that respect.

Yes.

> But who would want to suppress RVOs in favor of move
> construction, anyway?

No-one, clearly. And Yes, all modern compilers support at least some RVO.
I am just not sure whether this SOME is enough in all cases. I'd love to
believe it is, but I am a bit scheptical.

>
>> You still need to convert to temporary in initializer lists, since
>> you cannot use the assigment constructor there, but most likely you
>> would have to do it anyway.
>
> Is that just speculation? I can't understand why you'd make that
> claim, since the CWG thinks that a prohibition on copying rvalues is
> possible.

I believe we are talking about two different things here. I was thinking
about cases where you have a movable class with movable members.

        class X : public movable<X>
        { ... };

        class Y : public movable<y>
        {
        X x;
        public:
        Y(move_from<Y> y) : x(move_from<X>(y.x)) {}
                              ^^^^^^^^^^^^^^^^^

clearly, "Y(move_from<Y> y) : x(y.x) {}" would not be able to move from x
since in this context y.x is an lvalue.

>
>>> The point is that if you want to use macros (or copy-and-paste) to
>>> generate the two overloads for (T& rhs) and (const_lvalue<T> rhs), you
>>> can have a problem trying to re-use the initializer list and body of
>>> the function because T& and const_lvalue<T> have different interfaces.
>>> With the appropriate conversion operator on const_lvalue,
>>> implicit_cast<T const&>(rhs) is the same thing in both cases and can
>>> be used to make initializer lists and bodies that can be reused.
>>
>> Oh, right! There is probably no way around explicitly writing both
>> constructors
>
> I just got finished describing how it could be done using
> implicit_cast. Did you not understand that?

Sorry, didn't parse the last part correctly.
You are right, if "const_lvalue" is convertible to T&, you can force the
conversion in both initializer lists and still use a single macro. But it
would still be the user's duty to explicitly force the conversion in
initializer list, wouldn't it?
I am not sure wether it is easier on the user to have him force a conversion
in a situation that he normally would not than just tell him that he needs
two separate constructors, one for const and one non-const lvalues.

>> but you can avoid duplication by putting the constructor's body in a
>> private member function and forward from both constructors to it.
>> At least that is what I have been doing.
>
> If it were that easy you could do it with macros by inserting a
> surrounding brace pair and initializing a T const& there.
> Unfortunately, it doesn't handle the initializer list and I almost
> never have code in the ctor body.

Yes users would still have to provide the initializer lists. Clearly
delegating the construction is worth only if the constructor has a
non-trivial body


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