Bug 52901 - invalid rvalue reference
Summary: invalid rvalue reference
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.6.1
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-04-07 16:35 UTC by michlemken
Modified: 2023-12-30 02:22 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments
code (330 bytes, text/x-c++src)
2012-04-07 16:35 UTC, michlemken
Details

Note You need to log in before you can comment on or make changes to this bug.
Description michlemken 2012-04-07 16:35:24 UTC
Created attachment 27111 [details]
code

A different result - just reordering the cout output.

#include <iostream>
using namespace std;
 
struct X {
        int value;
        X() {
                cout << "default construction" << std::endl;
                value = 0;
        }
        X(const X& other) {
                cout << "copy construction" << std::endl;
                value = 1;
        }
        X(X&& other) {
                cout << "move construction" << std::endl;
                value = 2;
        }
 
        X& operator = (const X& other) {
                cout << "assignment" << std::endl;
                value = 3;
                return *this;
        }
};
 
X&& f() {
        X x;
        return std::move(x);
}
 
int main() {
        cout << "Hello References [1]" << std::endl;
        X   x0 = f();
        cout << "x0: " << x0.value << std::endl;
        X&& x1 = f();
        cout << "No copy construction or assignment expected" << std::endl;
        cout << "x1: " << x1.value << std::endl;
 
        cout << "Hello References [2]" << std::endl;
        X   y0 = f();
        cout << "y0: " << y0.value << std::endl;
        X&& y1 = f();
        cout << "y1: " << y1.value << std::endl;
        cout << "No copy construction or assignment expected" << std::endl;
 
        return 0;
 }
 
// Seems g++ 4.6.1 is buggy:
// Hello References [1]
// default construction
// move construction
// x0: 2
// default construction
// No copy construction or assignment expected
// x1: 6295648
// Hello References [2]
// default construction
// move construction
// y0: 2
// default construction
// y1: 0
// No copy construction or assignment expected
Comment 1 Daniel Krügler 2012-04-08 13:48:57 UTC
I don't see what this example is supposed to demonstrate. the two lines

X&& x1 = f();

and

X&& y1 = f();

produce references to invalid memory, any access to that is undefined behaviour. You cannot impose any reliable constraints on the values such references.
Comment 2 Jonathan Wakely 2012-04-08 14:14:30 UTC
This is just a bug in your program, not G++

(In reply to comment #0)
> 
> X&& f() {
>         X x;
>         return std::move(x);
> }

This function is unsafe, it returns a reference to a local variable. You probably meant it to return X not X&&

It is effectively the same as:

X& f() {
   X x;
   return x;
}

(except G++ warns about that, because it's simpler)


> 
> int main() {
>         cout << "Hello References [1]" << std::endl;
>         X   x0 = f();
>         cout << "x0: " << x0.value << std::endl;
>         X&& x1 = f();

This reference is bound to a variable that went out of scope when f() returned.

>         cout << "No copy construction or assignment expected" << std::endl;
>         cout << "x1: " << x1.value << std::endl;

This accesses deallocated memory.

N.B. you don't even need to use std::move, the compiler will automatically select the move constructor to create the return value here:

X f()
{
   X x;
   return x;
}
Comment 3 Marc Glisse 2012-04-08 15:32:45 UTC
(In reply to comment #2)
> > X&& f() {
> >         X x;
> >         return std::move(x);
> > }
> 
> This function is unsafe, it returns a reference to a local variable. You
> probably meant it to return X not X&&
> 
> It is effectively the same as:
> 
> X& f() {
>    X x;
>    return x;
> }
> 
> (except G++ warns about that, because it's simpler)

Maybe this could be taken as a RFE for a warning with std::move? Many people learning C++11 are bound to try similar things. g++ warns for

return X();
return static_cast<X&&>(x);

but not

return std::move(x);

I expect the case of std::move to be important enough that if doing a generic warning is too hard, special-casing std::move could be worth the trouble (assuming it is easier).
Comment 4 Jonathan Wakely 2012-04-08 18:05:49 UTC
(In reply to comment #3)
> g++ warns for
> 
> return X();
> return static_cast<X&&>(x);
> 
> but not
> 
> return std::move(x);

Nor for

X& g(X& x) { return x; }

X& f() {
        X x;
        return g(x);
}


I opened PR 49974 to request a warning there, we don't need another :)
Comment 5 Jonathan Wakely 2012-04-08 18:09:06 UTC
See also PR 51066 and PR 51270 and PR 38958 for similar RFEs for better diagnostics about creating dangling references