https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59926

Jonathan Wakely <redi at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           See Also|                            |https://gcc.gnu.org/bugzill
                   |                            |a/show_bug.cgi?id=57176
         Resolution|---                         |INVALID
             Status|UNCONFIRMED                 |RESOLVED

--- Comment #4 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to Patrick Arnoux from comment #2)
> Derived f(Derived d) { return (d) ; }
> Derived g(Derived& d) { Derived e = d ; return (e) ; }
> Derived h(Derived d) { Derived e = d ; return (e) ; }
> 
> 
>         Derived r ;
>         Derived u ;
>         u = f(r) ;         // (A) Move Ctor to TmpObj, then Move Assign to u.
>         u = g(r) ;         // (B) Move Assign to u (No move ctor)
>         u = h(r) ;         // (C) Move Assign to u
>         Derived v = h(r) ; // (D) straight up 'rvo'
> 
> I would have expected case A to behave like B and C and I would ask

I don't think the standard allows that.

The initial copy of 'r' has to happen in the caller's scope, not inside the
function. And so it can't be constructed in the return slot, because the caller
doesn't know that the body of 'f' returns its parameter, rather than returning
some other object.

If the functions are defined inline and your objects don't have silly side
effects like printing messages to standard output for every member function (or
other side effects with observable behaviour that can't be optimized away),
then the compiler _will_ optimize it to more efficient code.


> if case D could eliminate rvo and do a Move Ctor instead, would that
> simplify the code generation.

That's not possible, for the same reason as above. The call to h(r) has to make
a copy in the caller's frame, and that obviously can't be a move because 'r'
can't be modified by calling h(r). Then in the body of h you make another copy,
which can't be changed to a move because the compiler isn't allowed to do that
to arbitrary copies (except in a return statement). If you want it to be a
move, write it as a move:

Derived h(Derived d) { Derived e = std::move(d) ; return (e) ; }

Of course that 'h' function is still unnecessarily inefficient, using 'f' with
RVO does what you want:

        Derived w = f(r) ;

0x7ffd118b2cbf Derived copy
0x7ffd118b2cb7 Derived move
0x7ffd118b2cbf Derived dtor

This copies 'r' to initialize the argument 'd' and then moves that directly
into 'w'.

The standard doesn't permit us to do anything different here, so I'm closing
this.

Reply via email to