Boost logo

Boost :

From: David Abrahams (dave_at_[hidden])
Date: 2004-04-19 10:35:43


Andrea Torsello <torsello_at_[hidden]> writes:

> 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?

Right. That said, for Intel C++ I am not providing any X(X const&)
ctor, because it acts like comeau in non-strict mode (except that it
doesn't warn either), and thus will optimize direct initializations
when I am using the fancy move ctors.

>> 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.

My library is not relying on it being enough. It's just turning off
the mechanisms needed for non-RVO'ing compilers where appropriate.

>>> 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.

That's what the explicit "move(x)" function is for:

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

>>> 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?

When required. Sometimes you can rely on the implicit conversion.

> 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.

Considering that most/all of my ctors' logic is in the initializer
list and that the two ctors' initializers will be different, I like
having a way to make them the same.

>>> 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.

Only one initializer list need be provided, using implicit_cast<> if
neccessary.

> Clearly delegating the construction is worth only if the constructor
> has a non-trivial body

Yep.

-- 
Dave Abrahams
Boost Consulting
http://www.boost-consulting.com

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