user14859499
user14859499

Reputation:

How can a pointer be an rvalue?

#include <iostream>

void func(int*&& ptr)
{
    int j = 0;
    ptr = &j;
}

int main()
{
    int i = 0;
    std::cout << &i << std::endl;
    func(&i);
    std::cout << &i;
}

Pointless program I know, but I am just trying to learn.

Expected output: First cout to print the memory location to i and the second cout would print the memory location of temporary variable in which j was stored.

Actual output: Both memory locations that are printed are the same (which means it was unaltered by func)

At first, I tried defining func with single & like this void func(int*& ptr). My hope was this this being an lvalue reference would allow me to change the address of i. But this gives an error when I try to call the function as func(&i);, with a red wiggly under & and the error was.

initial value of a reference to non const must be an lvalue

Now here's my question. How can &i not be an lvalue? Isn't it a memory address? Doesn't that mean it defiantly is stored somewhere in memory? With the original function that I showed with rvalue reference(void func(int*&& ptr)), what that even mean? A memory address that isn't stored in memory?

Upvotes: 4

Views: 336

Answers (1)

Asteroids With Wings
Asteroids With Wings

Reputation: 17454

Let's put aside that "definitely stored somewhere in memory" doesn't strictly apply to any object in C++ (which is an abstraction over computer programming, not actual computer programming!), as that's not really the point here.

Though the int refered to by the name i is an object that "exists in memory somewhere", the temporary pointer you get with the expression &i is not. It's the unnamed result of an operation, like 2 + 3 or foo(). It's an rvalue expression.


what that even mean? A memory address that isn't stored in memory?

Basically, yeah.

The address of a thing, and the thing itself, are two different objects. Just because the thing is in memory, doesn't mean something that represents the address of that thing is also in memory.

This isn't actually an odd concept. You can find your house on a street, made of bricks and mortar, but if you try to find your postal address written on the road in chalk you're probably going to be looking for a long time.

Still, C++ lets you do that: the pointer can become a structure on the street in its own right, too, with a little more work. If you'd assigned &i to a new int* variable, the name of that variable would be an lvalue expression. You could therefore pass that pointer variable by reference into func. Perhaps now it's written in printer ink on a notice at the bus stop.

Notice that you already did precisely this with the int: 0 is an rvalue with no "memory address", but once you'd assigned it to a variable with a name (i), you had an lvalue to play with.


The value categories of expressions aren't something you can "see", so it can be a little tough to get to grips with them at first. You start by considering them to be "things that might be on the left-hand side of a = operation", with a bit of "things with names" sprinkled in. Eventually you come to find them intuitive, understand all their nuances, and drop the slightly inaccurate memory phrases. In the meantime, you can always come here and ask questions like this. 🙂

Upvotes: 2

Related Questions