注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

The Bloom of Youth

本博客已搬家至http://kuangqi.me

 
 
 

日志

 
 

[转]C++中临时变量不能作为非const的引用参数  

2009-08-30 22:01:12|  分类: 真回收站 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

原文出处:http://richardli1437.spaces.live.com/blog/cns!78FF174773FC6389!306.entry

试看下面的代码:

#include <iostream>

using namespace std;

void f(int &a) {

     cout << "f(" << a  << ") is being called" << endl;

}

void g(const int &a) {

     cout << "g(" << a << ") is being called" << endl;

}

int main() {

 int a = 3, b = 4;

 f(a + b);  //编译错误,把临时变量作为非const的引用参数传递了

 g(a + b);  //OK,把临时变量作为const&传递是允许的

}

上面的两个调用之前,a+b的值会存在一个临时变量中,当把这个临时变量传给f时,由于f的声明中,参数是int&,不是常量引用,所以产生以下编译错误:

const_ref.cpp: In function `int main()':

const_ref.cpp:14: error: invalid initialization of non-const reference of type '

   int&' from a temporary of type 'int'

const_ref.cpp:4: error: in passing argument 1 of `void f(int&)'

而在g(a+b)中,由于g定义的参数是const int&,编译通过。

 

问题是为什么临时变量作为引用参数传递时,必须是常量引用呢?很多人对此的解释是临时变量是常量,不允许赋值,改动,所以当作为非常量引用传递时,编译器就会报错。这个解释在关于理解临时变量不能作为非const引用参数这个问题上是可以的,但不够准确。

事实上,临时变量是可以被作为左值(LValue)并被赋值的,请看下面的代码:

#include   <iostream> 

using namespace std;

class CComplex {   

friend CComplex operator+(const CComplex &cp1, const CComplex &cp2);

friend ostream& operator<<(ostream &os, const CComplex &cp);

private: 

 int x; 

public: 

 CComplex(){}

  

  CComplex(int x1) { 

  x = x1; 

 }

};

 

CComplex operator+(const CComplex &cp1, const CComplex &cp2) { 

 CComplex cp3; 

 cp3.x = cp1.x + cp2.x; 

 return cp3; 

}

ostream& operator<<(ostream &os, const CComplex &cp) {

 os << cp.x;

 return os;

}

int main() { 

 CComplex a(2), b(3), c(4); 

 cout << (a + b) << endl;

 cout << ((a + b) = c) << endl;   //临时对象作为左值

 return 0; 

}

上面的程序编译通过,而且运行结果是:

4

5

临时变量确实被赋值,而且成功了。

所以,临时变量不能作为非const引用参数,不是因为他是常量,而是因为c++编译器的一个关于语义的限制。如果一个参数是以非const引用传入,c++编译器就有理由认为程序员会在函数中修改这个值,并且这个被修改的引用在函数返回后要发挥作用。但如果你把一个临时变量当作非const引用参数传进来,由于临时变量的特殊性,程序员并不能操作临时变量,而且临时变量随时可能被释放掉,所以,一般说来,修改一个临时变量是毫无意义的,据此,c++编译器加入了临时变量不能作为非const引用的这个语义限制,意在限制这个非常规用法的潜在错误。

还不明白?OK,我们说直白一点,如果你把临时变量作为非const引用参数传递,一方面,在函数申明中,使用非常量型的引用告诉编译器你需要得到函数对某个对象的修改结果,可是你自己又不给变量起名字,直接丢弃了函数的修改结果,编译器只能说:“大哥,你这是干啥呢,告诉我把结果给你,等我把结果给你了,你又直接给扔了,你这不是在玩我呢吗?”所以编译器一怒之下就不让过了。这下大家明白了吧?

 

那么,在函数中修改一个临时变量的引用是不是真的就毫无意义呢,其实也不尽然。在某些特定场合下,还是有意义的。比如我前几天在写一个高精度算法的类big_number,自然地,用了一个int数组nums[]存一个大数,而且为了提高效率,我还给了一个length指定位数,就是说这个大数就存在nums[0..length-1]里,其他的高位都是无效的,也省得我用big_number表示小数的时候一个个去填零。一开始,我定义加法如下:

big_number operator+(const big_number &n1, const big_number &n2);

但当我实现的时候,我想偷懒直接把n1和n2的低n1.length或n2.length(取决于哪个大)相加完事,这就得把短位数的大数补零,这样一来,就对n1或n2进行了修改,不能用const了,于是加法声明变成了:

big_number operator+(big_number &n1, big_number &n2);

虽然补了一些零,但由于nums[0..length-1]没便,他所表示的大数数值其实没变。这个声明和实现似乎也没什么问题。但当我用如下表达式时就出错了:

big_number n1, n2, n3, n4;

n4 = n1 + n2 + n3;

为什么呢?就是因为在计算n1+n2+n3的时候,先要算n1+n2,把值存到一个临时变量里tmp里,再去算tmp+n3,这时,tmp是一个临时变量,而我们只定义了

big_number operator+(big_number &n1, big_number &n2);

编译器不能把一个临时变量代入到一个非const的引用参数,所以他就找不到与之匹配的函数声明原型和实现,也就出错了:

test.cpp:6: error: no match for 'operator+' in 'operator+(big_number&, big_number&)((&n2)) + n3'

big_number.h:8: error: candidates are: big_number operator+(big_number&, big_number&)

怎么办呢,只好重新实现加法重载,做到真正的const引用,也就是在不修改n1,n2的情况下,算出结果。没法偷懒了,:( 所以说啊,c++编译器的这个语义限制虽好,但有时也挺累人的。

  评论这张
 
阅读(1422)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017