12

I was wondering, why the following way of code (Already commented out) will cause
C2102: '&' requires l-value

Is there a better way to avoid using tmp variable?

class a {
private:
    int *dummy;
public:
    int* get_dummy() const {
        return dummy;
    }
};

int main()
{
    a aa;

    // error C2102: '&' requires l-value
    //int** me = &(aa.get_dummy());

    // OK!
    int *tmp = aa.get_dummy();
    int** me = &(tmp);
}
Cheok Yan Cheng
  • 47,586
  • 132
  • 466
  • 875

5 Answers5

10

Because a::get_dummy() returns a unnamed temporary object (int pointer).
Object returned by function sit ontop of the stack frame and it is meaningless to get its address since it might be invalid after expression ends.

YeenFei
  • 3,180
  • 18
  • 26
  • Same issue as Luca's answer. `tmp` is a stack object! – Billy ONeal Sep 09 '10 at 07:22
  • `dummy` is not a temporary object or a local object. – Naveen Sep 09 '10 at 07:22
  • @Naveen: Yes, that is true. But the answer doesn't say "unnamed temporary" (which lives until the end of it's full expression), it says "stack object" which typically means an object in "automatic" storage which lives until the end of it's scope. – Billy ONeal Sep 09 '10 at 07:23
  • @Billy, added the "unnamed" onto my answer. but i dont see "stack object" in my reply that you are referring to. – YeenFei Sep 09 '10 at 07:29
  • 1
    @YeenFei: Stack object is implied by "top of the stack frame" and "out of scope". `tmp` is **also** invalid when it goes out of scope. Unnamed compiler temporaries have *absolutely nothing* to do with scope. They live until the end of their owning full expression. – Billy ONeal Sep 09 '10 at 07:33
  • @Naveen: We are not returning dummey (as that would require a reference). We are returning a copy of dummy (a pointer) as such it is not a variable and thus we can not take its address. So yes this is a temporary (think of it as a temporary pointer). – Martin York Sep 09 '10 at 07:35
  • @Billy, alright, i always referred "expression lifetime" as scope, guess that wasn't the word others use. – YeenFei Sep 09 '10 at 07:35
  • @YeenFei: Scope has a very specific meaning according to the standard. see section 3.3 for an exhaustive definition (which is 2 pages long). In this case, though, we are concerned only with block scope (section 3.3.3), which is "merely" half a page long. – Billy ONeal Sep 09 '10 at 07:48
  • @Billy, edited usage of "scope" in my answer to "expression". The "top of stack frame" remains true unless it is assigned to a reference (and new temporaries can be placed on top instead of over it). – YeenFei Sep 09 '10 at 08:16
  • "sit ontop of the stack frame" - not necessarily they might be stored in registers sometimes. – Огњен Шобајић Mar 27 '14 at 02:14
7

You could instead define:

int **get_dummy() ... return &dummy;

You can think of an r-value as an expression, essentially, whereas an l-value is an actual object. Expressions don't have addresses, and even if they did, it's hard to imagine what good the address would be. It's easy to understand how the address of an object can be useful.

It's a bit hard to understand an issue like this abstractly. The very best way to develop an understanding of pointers and compiled languages is to learn assembly language.

DigitalRoss
  • 143,651
  • 25
  • 248
  • 329
  • Hmm, you might be able to use `&aa`, but otherwise, why do you want the indirect pointer? Is there no API to change the pointer? Do you even want to change it? It's dangerous to take the address of a local variable... – DigitalRoss Sep 09 '10 at 07:21
  • be it global, member or local variable, as long as its lifetime exceed the referrer, the "danger" of dangling pointer is non-existent. – YeenFei Sep 09 '10 at 08:24
  • @YeenFei, sure, but returning a local's address is an exotic operation in any language. When people don't fully understand the run-time reality, staying on the more-obviously-safe side is probably a good idea. – DigitalRoss Apr 12 '16 at 00:35
4

No.

What address would me contain otherwise? Here you gave it the address of tmp -- but if you replace it with int** me = &aa.get_dummy();, where would it point?

There's no meaningful answer to that question, so the standard requires that the argument of & be an lvalue.

Billy ONeal
  • 104,103
  • 58
  • 317
  • 552
1

The compiler is right, according to ISO C++ § 5.3.1.3:

The result of the unary & operator is a pointer to its operand. The operand shall be an lvalue or a qualified-id.

In other words, you can take an address of anything that has a name.

Values returned from functions by-value have no name and are often returned via a register. So there is no "address" to speak of as the value is not residing in memory!

One could argue that the compiler could be smarter, detect this and store the value on the stack for the duration of the expression in which the address is used. But that is error-prone (you can "leak" a pointer to outside the expression), and would clearly be an extension of the standard (i.e. not guaranteed to be compatible). So MSVC simply prohibits it.

Entertainingly, the compiler is that smart when it comes to a reference to an rvalue. But there is no such functionality for a pointer to an rvalue.

To answer your question: try to minimize taking addresses of stuff; taking an address of a variable prevents the optimizer from putting it into a register. But if you have to, return a reference instead:

class a {
private:
    int dummy;
public:
    int get_dummy() const {
        return dummy;
    }
    int& get_dummy() {
        return dummy;
    }
};

int main()
{
    a aa;

    int* me = &(aa.get_dummy());
}

Note that having a const get_dummy() is not strictly needed, but will help the optimizer in rvalue contexts.

rustyx
  • 80,671
  • 25
  • 200
  • 267
0

The & operator must be applied to an lvalue. When the call aa.get_dummy() is not assigned to a variable, its return value is only put on the stack, so it would be silly (and erroneous) to get the address of a stack item.

Luca Martini
  • 1,434
  • 1
  • 15
  • 35