4

I was looking around the net and found an article which tries to explain std::move and rvalues and found something I really can't grasp.

int i = 42; 
i = 43; // ok, i is an lvalue 
int* p = &i; // ok, i is an lvalue 
int& foo(); 
foo() = 42; // ok, foo() is an lvalue 
int* p1 = &foo(); // ok, foo() is an lvalue

What's the point of int& foo()? What is foo() = 42 in this example?

EDIT: Since the part that got me confused and doesn't have anything to do with rvalues I'll write the part that solved my problem:

I didn't know you could write function declarations inside scopes so int& foo() became a int reference with empty initializer which also is impossible since references must point to something. But in the heat of the moment I went full .......

2 Answers2

5

int& foo() is a function returning a (lvalue) reference to an integer.

A reference is like a pointer, but unlike a pointer it has no identity of its own. It is an alias to its target, instead of the address of its target, logically.

Often references are implemented as pointers, but the point of references is that often the compiler can remove their existence entirely. Doing so with pointers is often more difficult, because they have an identity separate from what they refer to.

There is no way in C++ to get the address of a reference. You can get the address of a structure containing a reference, which is so close as makes no difference, but you cannot get the address of the reference itself.

int& foo() returns a reference to an integer. As an example:

int x=0, y=0;
bool pick_x=true;
int& foo() { if (pick_x) return x; else return y; }

now foo returns a reference to either of x or y depending on the state of pick_x.

You can use the return value of foo almost exactly as if it was x (or y if !pick_x.)

lvalue and rvalue come from the days of C. An lvalue is an expression that can go on the left or right of an = sign, and an rvalue is an expression that can only go on the right of an = sign.

In many languages, lvalue and rvalue can be expressed in the grammer. In C++, the existence of reference means that the return value of an expression can be a valid thing to assign to, and the existence of overloaded operator= means that rvalues can sometimes be assigned to. So things get tricky.

In C++11, lvalue reference and rvalue references where added. Each refuse to bind to the other type of expression. There are also forwarding references, which mainly occur in template type deduction.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • Dude i know what references are. I though foo was a reference to a int with empty default initializer inside main or something since he used foo() = 42 below in the example. My point was that int& foo() is useless since it doesn't point to anything and foo() = 42 doesn't make any sense at all and thats the part that made me question if i know c++ at all. Also if int& foo() was a function it would return the address of a local variable which then would be UB. –  Jul 19 '15 at 00:32
  • @newone: Er... "int& foo() is useless since it doesn't point to anything..." What is that supposed to mean? References in C++ are always bound to something. Where did you get the idea that the result of `foo()` is not bound to anything??? – AnT stands with Russia Jul 19 '15 at 00:34
  • if you write int& foo(); inside main and main only and compile it, what is foo? –  Jul 19 '15 at 00:36
  • 1
    @newone : What's `foo` will depend on how `foo` is defined. Every function in C++ has to be defined, if it is used in the code. The code in your original question does not provide a definition for `foo` simply because it does not matter. But it implies that the definition exists somewhere, of course. – AnT stands with Russia Jul 19 '15 at 00:38
  • 3
    @newone: `int& foo();` is a function declaration. The function needs to be defined somewhere though, otherwise you will get a linker error. I presume the person who wrote the snippet in that article assumed the readers understood that, and decided not to explicitly define the function, because the actual definition wasn't important to what was being explained by the article. – Benjamin Lindley Jul 19 '15 at 00:39
  • man i screwed my own brain so much trying to figure out rvalue vs lvalues that i forgot that references must point to something. So i rly though int& foo() was wicked if it was inside main and i actually didn't know you could write function declarations inside main and I don't see the purpose of doing it inside main still. –  Jul 19 '15 at 00:41
  • @newone: Your original post does not even have a `main`. Where did the matter of `int& foo()` being "inside main" suddenly came from? – AnT stands with Russia Jul 19 '15 at 00:44
  • 1
    It was a qualified guess based on the article. I first though foo() was referring to a function, then I though, well he is declaring alot of variables so why do them global (bad practice lol) so I though well, they must be inside a function scope. So int& foo() became a reference with empty initializer (since i actually didn't know you could write declarations inside scopes) and this idiotic thread was born. –  Jul 19 '15 at 00:48
  • @Benjamin Lindley That answers my question mate. I didn't get any linker error (tried with both gcc and msvc++) otherwise I would have guessed it was a declaration inside function scope which i didn't know you could do. Well i learned something new today cheers –  Jul 19 '15 at 01:00
2

The semantics of non-const lvalue reference is exactly the same as the semantics of an ordinary pointer, expect that pointer require an * operator to dereference it, while a reference does not.

So your

int& foo();
foo() = 42;

can be re-expressed in terms of pointers as

int* foo();
*foo() = 42;

If you don't see anything strange or unusual in the second piece of code, then you should not see anything strange or unusual in the first one.

For example

int i;

int &foo() { return i; }
int *bar() { return &i; }

int main()
{
  foo() = 42;
  assert(i == 42);

  *bar() = 24;
  assert(i == 24);
}
AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765