2

I'm reviewing code and which looks kind of wrong to me. I know it can be written in another way and I know it is probably useless to write it this way. Still, I was surprised that the compiler didn't generate any error/warning so I wonder if it is legal and why.

struct A
{
    int val = 0;
    int* GetVal() {
        return &val;
    }
};

void main()
{
    A a;
    int* const& r = a.GetVal();
}

AFAIK, a reference represents a real variable. The reference and the variable should both have the same memory address. In this example, there is no variable holding the address (maybe a temporary?) so which variable does r refer to?

If I remove the const it doesn't compile.

Gils
  • 478
  • 2
  • 9
  • 2
    Where is the instantiation of `a` actually? Your example is incomplete. – πάντα ῥεῖ Aug 28 '19 at 19:24
  • That's exactly the same for `int f(); int const& n = f();`... – Aconcagua Aug 28 '19 at 19:25
  • Have a look at [this answer](https://stackoverflow.com/a/2784304/1312382). Context of the question there actually is a bit different, but the answer fits for your question as well (prolongation of life-time via const local references). – Aconcagua Aug 28 '19 at 19:27
  • @πάντα ῥεῖ Thanks. fixed. – Gils Aug 28 '19 at 19:28
  • In this case `r` refers to the pointer. The pointer points at an instance of `A::val` – user4581301 Aug 28 '19 at 19:32
  • @user4581301 yes indeed, but the pointer is defined implicitly by the compiler (and not by me) and is hidden in the stack. – Gils Aug 28 '19 at 23:32
  • Hidden somewhere, probably the stack. Might sit in a register since you're not taking the pointer's address. Automatic storage can get a bit weird. – user4581301 Aug 29 '19 at 00:52

1 Answers1

6

There's one special case with references: a const reference is allowed to be bound to a temporary object, and it extends the lifetime of that temporary. Non-const references can't do this magic.

In your code, GetVal() returns a pointer by value, that is it returns a temporary pointer object. When used as a const reference initializer, the compiler stores that pointer value somewhere (most likely in the current stack frame) and binds the reference to that location.

Igor G
  • 1,838
  • 6
  • 18
  • +1 I didn't know this was possible. But this means that the usage/functionality of a const reference to a temporary are **exactly the same** as just copying the value? Except that you cannot overwrite the reference, where just storing the object would allow you to do so? – Martijn Courteaux Aug 28 '19 at 19:29
  • @Igor G thanks for the super quick response. I checked the stack the "hidden" variable is indeed there. I just wondered if it is legal. – Gils Aug 28 '19 at 19:31
  • @Gils Beware that this only works in certain situations. Only `const T &` allow it and only local references. For example, a reference type class member won't work this way. – François Andrieux Aug 28 '19 at 19:32
  • @MartijnCourteaux, I would say that const reference can help _avoiding_ making a copy. Consider passing a temporary object to `f(Type)` and `f(const Type&)`. – Igor G Aug 28 '19 at 19:35
  • @François Andrieux I don't think I ever used this feature (at least not in this way). That's why it looks so wrong to me. I find the reference mark redundant in this case. I was just surprised it is legal. – Gils Aug 28 '19 at 19:39
  • @Gils You're using it (maybe without knowing) everytime you pass a `"text"` to a function requiring a `const std::string&`, a `std::string` temporary gets created and it's lifetime is extended for the duration of the function call. – Mirko Aug 28 '19 at 19:58
  • @Mirko Indeed. Coming to think about, I use it a lot. Each time I pass an rvalue to a const reference parameter. But never like in this example. I still find this use of reference like in this example, useless. – Gils Aug 28 '19 at 23:30