public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug c++/59926] New: Remove temporary move constructor before move assignment
@ 2014-01-23 18:11 arnoux123 at gmail dot com
  2014-01-23 18:14 ` [Bug c++/59926] " redi at gcc dot gnu.org
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: arnoux123 at gmail dot com @ 2014-01-23 18:11 UTC (permalink / raw)
  To: gcc-bugs

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

            Bug ID: 59926
           Summary: Remove temporary move constructor before move
                    assignment
           Product: gcc
           Version: unknown
            Status: UNCONFIRMED
          Severity: enhancement
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: arnoux123 at gmail dot com

When returning an rvalue from a function, the compiler creates a temporary
using
"move constructor" before doing a "move assignment" to the object in the
calling
function. See code below.
Would it be possible to remove this temporary "move constructor" which seems
somewhat redundant.

#include <iostream>
#include <utility>
#include <string>

class Base
{
public:
        Base() { std::cout << this << " Base ctor\n" ; }
        ~Base() { std::cout << this << " Base dtor\n" ; }
        Base(Base const&) { std::cout << this << " Base copy\n" ; }
        Base& operator=(Base const&) { std::cout << this << " Base copy
assign\n" ; return *this; }
        Base(Base&&) { std::cout << this << " Base move\n" ; }
        Base& operator=(Base&&) { std::cout << this << " Base move assign\n" ;
return *this; }
};

class Derived : public Base
{
public:
        Derived(): Base() { std::cout << this << " Derived ctor\n" ; }
        ~Derived() { std::cout << this << " Derived dtor\n" ; }
        Derived(Derived const& o): Base(o) { std::cout << this << " Derived
copy\n" ; }
        Derived(Derived&& o): Base(std::move(o)) { std::cout << this << "
Derived move\n" ; }
        Derived& operator=(Derived const& o) { std::cout << this << " Derived
copy assign\n" ; return (*this) ; }
        Derived& operator=(Derived&& o) { std::cout << this << " Derived move
assign\n" ; Base::operator=(std::move(o)) ; return (*this) ; }
};

Derived f(Derived d) { return (d) ; }

int main()
{
        Derived r ;
        Derived u ;
        u = f(r) ;
        return 0;
}


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [Bug c++/59926] Remove temporary move constructor before move assignment
  2014-01-23 18:11 [Bug c++/59926] New: Remove temporary move constructor before move assignment arnoux123 at gmail dot com
@ 2014-01-23 18:14 ` redi at gcc dot gnu.org
  2014-01-23 22:15 ` arnoux123 at gmail dot com
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: redi at gcc dot gnu.org @ 2014-01-23 18:14 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #1 from Jonathan Wakely <redi at gcc dot gnu.org> ---
This looks like PR 57176


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [Bug c++/59926] Remove temporary move constructor before move assignment
  2014-01-23 18:11 [Bug c++/59926] New: Remove temporary move constructor before move assignment arnoux123 at gmail dot com
  2014-01-23 18:14 ` [Bug c++/59926] " redi at gcc dot gnu.org
@ 2014-01-23 22:15 ` arnoux123 at gmail dot com
  2024-03-17  4:49 ` pinskia at gcc dot gnu.org
  2024-03-25 12:43 ` redi at gcc dot gnu.org
  3 siblings, 0 replies; 5+ messages in thread
From: arnoux123 at gmail dot com @ 2014-01-23 22:15 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #2 from Patrick Arnoux <arnoux123 at gmail dot com> ---
(In reply to Jonathan Wakely from comment #1)
> This looks like PR 57176

Thank you for the reference to PR 57676.
Delving into this a bit further, I found the following:

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
if case D could eliminate rvo and do a Move Ctor instead, would that
simplify the code generation.


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [Bug c++/59926] Remove temporary move constructor before move assignment
  2014-01-23 18:11 [Bug c++/59926] New: Remove temporary move constructor before move assignment arnoux123 at gmail dot com
  2014-01-23 18:14 ` [Bug c++/59926] " redi at gcc dot gnu.org
  2014-01-23 22:15 ` arnoux123 at gmail dot com
@ 2024-03-17  4:49 ` pinskia at gcc dot gnu.org
  2024-03-25 12:43 ` redi at gcc dot gnu.org
  3 siblings, 0 replies; 5+ messages in thread
From: pinskia at gcc dot gnu.org @ 2024-03-17  4:49 UTC (permalink / raw)
  To: gcc-bugs

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

--- Comment #3 from Andrew Pinski <pinskia at gcc dot gnu.org> ---
GCC and clang produce the same output ...

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [Bug c++/59926] Remove temporary move constructor before move assignment
  2014-01-23 18:11 [Bug c++/59926] New: Remove temporary move constructor before move assignment arnoux123 at gmail dot com
                   ` (2 preceding siblings ...)
  2024-03-17  4:49 ` pinskia at gcc dot gnu.org
@ 2024-03-25 12:43 ` redi at gcc dot gnu.org
  3 siblings, 0 replies; 5+ messages in thread
From: redi at gcc dot gnu.org @ 2024-03-25 12:43 UTC (permalink / raw)
  To: gcc-bugs

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.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2024-03-25 12:43 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-01-23 18:11 [Bug c++/59926] New: Remove temporary move constructor before move assignment arnoux123 at gmail dot com
2014-01-23 18:14 ` [Bug c++/59926] " redi at gcc dot gnu.org
2014-01-23 22:15 ` arnoux123 at gmail dot com
2024-03-17  4:49 ` pinskia at gcc dot gnu.org
2024-03-25 12:43 ` redi at gcc dot gnu.org

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).