关于返回临时变量的疑惑

ithiker 2010-05-19 09:35:37

class X
{
int i;
public:
X(int ii = 0);
void modify();
};

X::X(int ii)
{
i = ii;
}

void X::modify()
{
i++;
}

X f5()
{
return X();
}
const X f6()
{
return X();
}

void f7(X& x)
{
x.modify();
}

int main()
{
f5() = X(1);//ok
f5().modify();//ok

f7(f5());//warning

f6() = X(1);//error
f6().modify();//error
f7(f6());//error

return 0;
}

这是《Thinking in C++》上的一个例题,它的讲解有点不明白。
既然f5()返回的是一个临时变量,为什么f5()=X(1)还OK?
好像以前还看过返回的类对象临时变量是常量这一说,如果是这样,上面就更不正确了
...全文
342 23 打赏 收藏 转发到动态 举报
写回复
用AI写文章
23 条回复
切换为时间正序
请发表友善的回复…
发表回复
swift19221 2011-08-17
  • 打赏
  • 举报
回复
临时变量是只读的吧?
我也遇到了这个问题。

//函数定义
bool writeLog(string& strLogMsg){....}

这样调用会有问题:
writeLog(string("this is log for test"));
说参数不匹配,是不是因为 临时变量string("this is log for test")是只读的,
所以不能传递给 string&形参,

把函数定义改为:
bool writeLog(const string& strLogMsg){....}
就没有问题了!!

说明:在vs2008编译器下没问题,但是在mingw32编译器下会有上述的问题
lllsui 2010-05-20
  • 打赏
  • 举报
回复
o o
patricxuqi 2010-05-20
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 pgplay 的回复:]
LZ你太心急了,你要的答案在《Thinking in C++》后面的章节中(第十一章)有一个更深入的解释,简单来说,对于返回内置类型的函数比如int f();其返回值是被放入寄存器中返回的,因此,你不能修改返回值(因为返回值在寄存器中)

而对于类类型对象:X x = f();
函数加载时是把返回的地址(x的地址)也像参数一样压入栈,返回时直接放在目的地(x)。因此,你能修改(因为返回值在栈……
[/Quote]
返回值存放在EAX里面。用alt+8查看一下就知道了。
wjlsmail 2010-05-20
  • 打赏
  • 举报
回复
const X f6()

被const 修饰,所以不能当左值。
ithiker 2010-05-19
  • 打赏
  • 举报
回复
谢谢各位了
特别感谢Vegertar和pgplay兄~
Vegertar 2010-05-19
  • 打赏
  • 举报
回复
实际上, 就底层对象的放置而言,只有编译时常量才会放到常量区,由操作系统进行直接的只读标记,而其他变量通过一些手段都是可写的(必须要有权限),而对于 A() ,不管其是放到 stack, heap, data 区,首先它是一个匿名对象,想要直接的引用,要不就是 A().method() 方式,要不就是显式 declare 一个名字,前面已经说过,编译器只会允许你使用一个常量的名字去引用它。
所以,就 A() 本身而言,它是一个普通对象,本身没有任何属性,只是生命期短了一些,而想长久的操纵它,只能通过一个只读的名字。
ithiker 2010-05-19
  • 打赏
  • 举报
回复
to 2楼
我用的是c-free 5.0,上网瞎碰的一个汉化编译器,15M左右大小,界面感觉很好

专门测试了下
在vc6.0上会报错
在codeblocks上不会
ithiker 2010-05-19
  • 打赏
  • 举报
回复
to 6楼
这个没看过,能否具体些...

to 8楼

1.“如A &r = A();
是因为A()的生命期太短(到分号处就析构),r 的引用是未定义这一点是完全可预测的,所以语言规则可强制prevent ”
2.“ const A &r = A(); 合法是因为 const 引用是作特别处理的,可延长临时对象的生命期。”
 
int main()
{
X &a=f5(); /*error: invalid initialization of non-const
reference of type 'X&' from a temporary of type 'X' */
const X &b=f5();//ok
f5().i = 123;//ok
f5().modify();//ok

return 0;
}

分析的很好
代码说明了prevent的正确性。说明non-const引用不能绑定到临时对象上。
本书的前面一点讲const时说,如果取一个const常量的地址会创建该变量(为该const变量分配空间);引用和地址紧密联系,这个特殊处理我估计类似,就是在main的作用域内创建该变量。
但感觉这二点也说明临时对象是常量,要不然不创建该变量就不能延长临时对象的生命期,不知道对不对?

to 9楼
谢谢分析,我还没看到后面,一时有点理解不了栈和寄存器的区别
we_sky2008 2010-05-19
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 unicodexinyi 的回复:]
引用 13 楼 we_sky2008 的回复:

引用 11 楼 gigglesun 的回复:
书上还接着解释:f5()必须返回一个临时变量来保存临时值,在上面的表达式中,临时对象被修改了,当f5() = X(1);这个表达式运行完后,临时对象就被清空了,丢失了所有的信息,上面的赋值因此也就没有任何意义。

to 1楼:
“会直接在返回值的地址上建一个对象:”这个对象是临时的吗?前面看……
[/Quote]
呵呵
可以看下我以前发的帖子:http://topic.csdn.net/u/20100111/15/bc95ff6b-171a-4d9f-ab0a-59cb4d04f749.html
KudoCC 2010-05-19
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 we_sky2008 的回复:]

引用 11 楼 gigglesun 的回复:
书上还接着解释:f5()必须返回一个临时变量来保存临时值,在上面的表达式中,临时对象被修改了,当f5() = X(1);这个表达式运行完后,临时对象就被清空了,丢失了所有的信息,上面的赋值因此也就没有任何意义。

to 1楼:
“会直接在返回值的地址上建一个对象:”这个对象是临时的吗?前面看过的有点记不住了。

to 2楼
修改后也不会……
[/Quote]
握手,我也是,哈哈
we_sky2008 2010-05-19
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 gigglesun 的回复:]
书上还接着解释:f5()必须返回一个临时变量来保存临时值,在上面的表达式中,临时对象被修改了,当f5() = X(1);这个表达式运行完后,临时对象就被清空了,丢失了所有的信息,上面的赋值因此也就没有任何意义。

to 1楼:
“会直接在返回值的地址上建一个对象:”这个对象是临时的吗?前面看过的有点记不住了。

to 2楼
修改后也不会出错
[/Quote]
不会吧?
你用的什么编译器?
我刚才试了一下,VC6会报错的:error C2106: '=' : left operand must be l-value
KudoCC 2010-05-19
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 gigglesun 的回复:]

书上还接着解释:f5()必须返回一个临时变量来保存临时值,在上面的表达式中,临时对象被修改了,当f5() = X(1);这个表达式运行完后,临时对象就被清空了,丢失了所有的信息,上面的赋值因此也就没有任何意义。

to 1楼:
“会直接在返回值的地址上建一个对象:”这个对象是临时的吗?前面看过的有点记不住了。

to 2楼
修改后也不会出错
[/Quote]
顶啊,不过你回复2L说的我试了

看10L
ithiker 2010-05-19
  • 打赏
  • 举报
回复
书上还接着解释:f5()必须返回一个临时变量来保存临时值,在上面的表达式中,临时对象被修改了,当f5() = X(1);这个表达式运行完后,临时对象就被清空了,丢失了所有的信息,上面的赋值因此也就没有任何意义。

to 1楼:
“会直接在返回值的地址上建一个对象:”这个对象是临时的吗?前面看过的有点记不住了。

to 2楼
修改后也不会出错
KudoCC 2010-05-19
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 we_sky2008 的回复:]

f5()=X(1);
这里调用的是类X的缺省的赋值函数逐成员赋值。

楼主可以测试:
将X的数据成员i改为public
然后f5().i = 123;
这种情况就会编译出错
[/Quote]
编译出错的原因是(f5()).i不能作为左值,我很奇怪啊
耍宝王 2010-05-19
  • 打赏
  • 举报
回复
LZ你太心急了,你要的答案在《Thinking in C++》后面的章节中(第十一章)有一个更深入的解释,简单来说,对于返回内置类型的函数比如int f();其返回值是被放入寄存器中返回的,因此,你不能修改返回值(因为返回值在寄存器中)

而对于类类型对象:X x = f();
函数加载时是把返回的地址(x的地址)也像参数一样压入栈,返回时直接放在目的地(x)。因此,你能修改(因为返回值在栈上(可能是临时的,比如:直接调用f();而没有给出存放的变量))
Vegertar 2010-05-19
  • 打赏
  • 举报
回复
对自定义对象而言,临时对象并非是常量(没有const限定),不能赋值给非常量引用,如A &r = A();
是因为A()的生命期太短(到分号处就析构),r 的引用是未定义这一点是完全可预测的,所以语言规则可强制prevent ,
而 const A &r = A(); 合法是因为 const 引用是作特别处理的,可延长临时对象的生命期。
而 A().method(); 对其所有非常量方法都是有效的(显然 operator= 也属于此类),因为在其生命期内,这样的调用是完全符合语法的。
KudoCC 2010-05-19
  • 打赏
  • 举报
回复
1L说的不错,但是没解决Lz的问题

2L也没说清啊

我还是顶lz吧,但是lz确定返回的临时变量是常量?
beginsoft_nj 2010-05-19
  • 打赏
  • 举报
回复
我记得应该是函数main的栈里预先创建了X的临时对象 只不过对我们隐藏了 f5()返回的临时对象应该是复制给它 所以在生命期里 没问题
zyrr159487 2010-05-19
  • 打赏
  • 举报
回复
这是赋值,相当于NEW了一个X(1)
RHuniSoft 2010-05-19
  • 打赏
  • 举报
回复
差不多了。。。。
class X
{
int i;
public:
X(int ii = 0);
void modify();
};
X::X(int ii)
{
i = ii;
}

void X::modify()
{
i++;
}

X f5()
{
return X();
}
const X f6()
{
return X();
}

void f7(X& x)
{
x.modify();
}

int main()
{
f5() = X(1);//ok
f5().modify();//ok

f7(f5());//warning,我这没报警告,可能是级别的问题,嵌套的好深

f6() = X(1);//error,这个地方你用非const赋给const X会报错呀
f6().modify();//error,还是那个问题呀,你f6()返回了一个const X,X.modify()的i不能在变化了呀
f7(f6());//error,同上,const X不能赋值给非const X的引用const同非const之间不能简单的相互赋值

return 0;
}
加载更多回复(3)

64,646

社区成员

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

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