惊讶!返回类实例的函数,其返回值竟然是左值?

motzyd 2011-08-11 06:26:56
一直以为,只有返回引用的函数,其返回值才是左值,才可以被赋值,被取地址,但是看effective c++ 3rd发现不是这么回事,用vc++实验,还真是令我惊讶!

R {
};

R f()
{
return R();
}

int f2()
{
return 8;
}

int main()
{
R a;
f() = a; // ok!
f2() = 7; // error!
}

f() = a没问题,f2() = 7就错误,f()返回R实例,它可以被赋值吗?它是左值,那返回int的f2(),为什么不能被赋值,为什么不是左值呢?好困惑!
...全文
340 15 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
genio 2011-08-11
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 genio 的回复:]
引用 11 楼 motzyd 的回复:
引用 9 楼 genio 的回复:

引用 7 楼 motzyd 的回复:
能够取地址的都可以看作左值



你这么说,对C语言是正确的,对C++呢?你看&R()是可以的,但R()显然是右值

你的显然是错的,我前面一句说的很明白了
[/Quote]
其实呢,返回对象的函数是特例的左值表达式,所以最关键的还是看能不能取地址,这已经高度概括了,如果还不清楚就没办法了
genio 2011-08-11
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 motzyd 的回复:]
引用 9 楼 genio 的回复:

引用 7 楼 motzyd 的回复:
能够取地址的都可以看作左值



你这么说,对C语言是正确的,对C++呢?你看&R()是可以的,但R()显然是右值
[/Quote]
你的显然是错的,我前面一句说的很明白了
至善者善之敌 2011-08-11
  • 打赏
  • 举报
回复
其实我想说的是F(),呵呵
motzyd 2011-08-11
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 babilife 的回复:]

我回答完了,可以一定要结贴了

(1)为什么这个可以

首先明确一下概念什么叫左值,一般可以这样说:左值必须有相应的内存空间
R() = a;中的

R()返回类型为自定义类类型,在所谓的左值还是右值的标准概念里,他也是属于两不管的那一类,那可以看一下汇编代码,他返回的时候是否有内存空间呢
以下摘自网络:
,发现如果函数R()返回类对象,那么会在调用者函数main的栈帧中预留……
[/Quote]

你从对应的代码角度理解它,研究的很深入。不过请注意这里R()不是函数调用,R就是我定义的类,所以R()是个临时类对象,它显然是个右值,因为它没名字啊,它很快就消失,但在它短暂的存在期间,居然给它赋值了,取地址了。。。。
motzyd 2011-08-11
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 genio 的回复:]

引用 7 楼 motzyd 的回复:
能够取地址的都可以看作左值

[/Quote]

你这么说,对C语言是正确的,对C++呢?你看&R()是可以的,但R()显然是右值
至善者善之敌 2011-08-11
  • 打赏
  • 举报
回复
我回答完了,可以一定要结贴了

(1)为什么这个可以

首先明确一下概念什么叫左值,一般可以这样说:左值必须有相应的内存空间
R() = a;中的

R()返回类型为自定义类类型,在所谓的左值还是右值的标准概念里,他也是属于两不管的那一类,那可以看一下汇编代码,他返回的时候是否有内存空间呢
以下摘自网络:
,发现如果函数R()返回类对象,那么会在调用者函数main的栈帧中预留这个对象所需要的空间,然后在调用函数的时候,在把参数逆序压栈后,紧接着把预留的返回对象的地址压栈,然后调用函数func运行。函数func运行过程中,实际上是通过[ebp+8]取得把返回对象的地址后,对这个地址空间进行调用构造或者拷贝构造函数构造返回对象,然后再把这个地址写入eax进行返回。
从汇编代码上来看,函数的返回值是在调用者caller的栈帧中进行分配的,函数返回后并不会随着被调用者callee函数的退栈而丢失,这个地址空间会和caller的作用域相同,

也就是说他是有内存空间的,所以可以说他是个左值,为什么又说他是两不管那一类那,因为,C++标准中说只有返回引用类型才可以称之为左值,所以为此,争论不休,今天也没有个结果!

所以 你暂且把 R()当做左值来处理吧


2) int() = 3;
有了上面的基础很好理解这个为什么不行了

int()为内置类型,内置类型返回时没有内存空间,所以称之为右值,C++规定,右值是不能放在=号左边的



楼主结贴吧
genio 2011-08-11
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 motzyd 的回复:]
更简单的情况:

class R {};

.....

int main()
{
R a;
R() = a; //为什么可以?R()可以被赋值?它是左值还是右值?它没有名字,应该是右值,但它又能被赋值,出现在赋值号左边,
&R(); //这个也可以,为什么?

//但是下面的不行
int() = 3;
&int();
}

……
[/Quote]
能够取地址的都可以看作左值
motzyd 2011-08-11
  • 打赏
  • 举报
回复
Demon__Hunter你真是高手啊,我明白了,允许对象实例的临时变量调用它的成员函数,R()=a其实是调用R临时实例的缺省赋值成员函数,&R()则是调用缺省取地址构造函数,而对于整数,int()=3和&int()就不行,看来C++中并非能出现在=左边的就是左值?多谢了!
motzyd 2011-08-11
  • 打赏
  • 举报
回复
更简单的情况:

class R {};

.....

int main()
{
R a;
R() = a; //为什么可以?R()可以被赋值?它是左值还是右值?它没有名字,应该是右值,但它又能被赋值,出现在赋值号左边,
&R(); //这个也可以,为什么?

//但是下面的不行
int() = 3;
&int();
}

困惑! 请C++高手指点迷津


hacqing 2011-08-11
  • 打赏
  • 举报
回复

20分, 我可以拿4分?
至善者善之敌 2011-08-11
  • 打赏
  • 举报
回复
那楼主可以给分了,别落下我就行!
liutengfeigo 2011-08-11
  • 打赏
  • 举报
回复
木有研究过这问题.
pathuang68 2011-08-11
  • 打赏
  • 举报
回复
1楼和2楼解释得很清楚了。
机智的呆呆 2011-08-11
  • 打赏
  • 举报
回复
虽然c++标准允许 f()(因为返回一个 class type的对象) 这个表达式 来调用operator=这个成员函数来更改 f() 表达式返回临时对象的状态,但c++标准还是明确规定了f() 表达式是一个右值
Expressions such as invocations of constructors and of functions that return a class type refer to objects, and the implementation can invoke a member function upon such objects, but the expressions are not lvalues
c++左值的定义不仅仅是 可以放在=左边的定义了,比c复杂的多了。
机智的呆呆 2011-08-11
  • 打赏
  • 举报
回复
3.10 Lvalues and rvalues [basic.lval]

2 An lvalue refers to an object or function. Some rvalue expressions—those of class or cv-qualified class type—also refer to objects.47)

47) Expressions such as invocations of constructors and of functions that return a class type refer to objects, and the implementation can invoke a member function upon such objects, but the expressions are not lvalues.

个人理解上述意思是,函数返回一个临时对象,而实现可以调用这个对象的成员函数的。
但表达式是右值

65,186

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧