开发者

Why this is causing C2102: '&' requires l-value

开发者 https://www.devze.com 2023-01-15 04:25 出处:网络
I was wondering, why the following way of code (Already commented out) will cause C2102: \'&\' requires l-value

I was wondering, why the following way of code (Already commented out) will cause

C2102: '&' requires l-value

Is there a be开发者_如何学Ctter 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);
}


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.


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.


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.


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.


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消