C++之引用

参考文章
C++笔记–返回对象还是返回引用


引用


我们们发现,在C++中,有些成员函数返回的是对象,而有些函数返回的又是引用。
返回对象和返回引用的最主要的区别就是函数原型和函数头。
Car run(const Car &) //返回对象
Car & run(const Car &) //返回引用

  • 返回对象会涉及到生成返回对象的副本,这是调用函数的程序可以使用的副本,因此,返回对象的时间成本包括了调用复制构造函数来生成副本所需的时间和调用析构函数删除副本所需的时间。返回引用可以节省时间和内存。直接返回对象与按值传递对象类似,他们都生成临时副本。同样,返回引用与按引用传递对象类似,调用和被调用的函数对同一个对象进行操作。
  • 并不是总是可以返回引用的,当函数不能返回在函数中创建的临时对象的引用,因为当函数结束时,临时对象将消失,因此这种引用是非法的,在这种情况下,应返回对象,以生成一个调用程序可以使用的副本。
    如:
RMB& RMB::operator++()  
{  
    yuan++;  
    return *this;  
}  
RMB RMB::operator++(int)  
{  
    RMB temp(yuan);      //创建对象  
    yuan++;  
    return temp;          //返回对象的副本  
}  
  • 通用的规则是,如果函数返回在函数中创建的临时对象,则不要使用引用,如果先创建一个对象,然后返回改对象的副本,则可以使用返回对象,如上述第二种情况。
  • 然:如果需要将返回的临时对象复制给新的外部对象(复制构造函数),则可以返回引用。只是会警告”warning: reference to local variable ‘a’ returned”
  • 如果函数返回的是通过引用或指针传递给它的对象,则应当按引用返回对象。当按引用返回调用函数的对象或作为参数传递给函数的对象。如上面的第一种情况。

引用的原理 引用与取地址


曾经有一篇老外文章”如何编写一个比C语言更快的语言”中,提到了C语言缺少引用类型
所可能导致的效率降低.其中详细描述了引用和指针的区别,例如,正如大多数教材所误导你的,
“引用和指针在很多情况下实现一致”,都是通过一个指针来实现的,但以下情况不同:

int i=1;
int* p=&i;
*p=1;
int i=1;
int& p=i;
p=1;

这两段代码的区别,在于第一段代码中,编译器并不了解我们对i取地址”&”的行为
实际上只是希望之后可以对i赋值,而并不关心取地址本身这个操作,由于它无法
了解我们的目的所在(这段代码中可能能了解,但再复杂一点就不行了),因此编译器
将不得不让变量i持有一个栈上的内存空间,以便使i确实拥有一个地址可以被”&”,
而在第二段代码中,由于我们使用了引用,编译器将了解我们只是想通过某种方式
访问到i这个变量,而完全不关心i的地址,因此编译器可以根本不给变量i申请内存地址,
而是让i从头到尾都存放在某个寄存器中,使得对i的读写实际上都变成对寄存器的读写.
而根本不需要和内存交互.

也就是说,任何对取地址的操作,都会使编译器产生一种:”这个被取地址的变量一定要在内存里”的错觉.
例如,有时我们需要强制类型转换,经常遇见这种代码:

int32 i=0x313671;
//.................
float k=*(float*)&i;

我们的目的无非就是希望i中的每一个bit都被完整地复制到k中,而编译器不这样认为,编译器认为
你对i进行了&操作,那么i必然在内存中,这段代码就会产生内存读写操作.

C++中上例的正确方法应该是:

int32 i=0x313671;
union {
  int a;
  float b;
} conv;
conv.a=i;
float k=conv.b;

没有取地址操作,则编译器能对这段代码更好地优化.将i和k全部放入寄存器中.

同理的,C语言中经常有函数是如下形式:

typedef struct Data_tag {
.........
.........
.........
} Data;

void process(Data* y,Data* x){...};

.............
Data a,b;
process(&a,&b);

其中无论编译器决策process函数是否inline,C语言(C++同理)都会认为无论如何,对变量
a和b必须进行取地址的操作,在process函数中代表a和b的必须是指针而不是其他形式.
而这样:

struct Data {
.........
.........
.........
};

void process(Data& y,Data& x){...};

.............
Data a,b;
process(a,b);

时,如果编译器认为process函数不能inline,那么这两段代码的行为是一致的,但一旦遇到
可以inline process函数的情况,编译器会马上了解到我们在process函数中只是需要处理
a和b,而不在乎a和b的地址.编译器不需要创建一个指针来指向a和b的地址,而是直接在process函数
中使用a和b所在的地址就可以了.

所以在一些对性能要求严格的位置,到底是使用引用还是使用指针,是很有讲究的.
对于编译器来说,使用引用可能能够带来更多的优化空间(虽然自由度下降了).

求解C++中引用的实现原理

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值