为什么这会导致C2102:'&'需要l值

时间:2010-09-09 07:05:29

标签: c++

我很想知道,为什么以下代码方式(已经注释掉)将导致
C2102: '&' requires l-value

是否有更好的方法可以避免使用tmp变量?

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);
}

5 个答案:

答案 0 :(得分:7)

您可以改为定义:

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

基本上,您可以将r值视为表达式,而l值是实际对象。表达式没有地址,即使它们确实存在,也很难想象地址有多好。很容易理解对象的地址如何有用。

这样抽象地理解这个问题有点难。了解指针和编译语言的最佳方法是学习汇编语言。

答案 1 :(得分:4)

没有

me包含哪个地址?在这里,您为其指定了tmp的地址 - 但如果您将其替换为int** me = &aa.get_dummy();,它会指向哪里?

这个问题没有有意义的答案,所以标准要求&的论点是左值。

答案 2 :(得分:4)

因为a::get_dummy()返回未命名的临时对象(int指针)。
函数返回的对象位于堆栈框架的顶部,获取其地址毫无意义,因为在表达式结束后它可能无效。

答案 3 :(得分:0)

必须将&运算符应用于左值。当调用aa.get_dummy()未分配给变量时,其返回值仅放在堆栈上,因此获取堆栈项的地址将是愚蠢的(并且是错误的)。

答案 4 :(得分:0)

编译器是正确的,根据ISO C ++ § 5.3.1.3

  

一元&的结果operator是指向其操作数的指针。该   操作数应为左值或合格标识。

换句话说,您可以获取具有名称的任何地址。

从函数 按值 返回的值没有名称,通常通过寄存器返回。所以没有" 地址"可以说,价值并非存在于记忆中!

有人可能会争辩说编译器可能更聪明,检测到这一点并在使用地址的表达式期间将值存储在堆栈中。但这容易出错(你可以"泄漏"指向表达式之外的指针),并且显然是标准的扩展(即不保证兼容)。所以MSVC只是禁止它。

有趣的是,编译器is that smart涉及引用到rvalue。但是指针没有这样的功能到rvalue。

回答您的问题:尽量减少收集内容的地址;获取变量的地址可防止优化器将其放入寄存器。 但如果必须,请返回引用:

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());
}

请注意,并不严格需要const get_dummy(),但会帮助rvalue上下文中的优化器。