我很想知道,为什么以下代码方式(已经注释掉)将导致
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);
}
答案 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上下文中的优化器。