Self Summary: C++函数返回引用和指针的问题,局部对象与new对象的问题

C++的局部对象的概念:

作用域在局部范围内(例如函数)的对象。这样的对象可以把对象的引用或者指针存在栈中,随着函数的结束而销毁,而把创建的对象内容存在堆中。如果需要在堆上创建对象,要么使用new运算符,要么使用malloc系列函数。


而关键是理解好“自动存储”的概念[1]:


Object obj;


此时,obj是在栈上分配的吗?
要回答这个问题,我们首先要理解这个语句是什么意思。这个语句就是代表着,在栈上创建对象吗?其实,这行语句的含义是,使对象obj具有“自动存储(automatic storage)”的性质。所谓“自动存储”,意思是这个对象的存储位置取决于其声明所在的上下文。如果这个语句出现在函数内部,那么它就在栈上创建对象。如果这个语句不是在函数内部,而是作为一个类的成员变量,则取决于这个类的对象是如何分配的。


例如:

Object *pObj;  
pObj = new Object;  


Object *pObj;代表,指针pObj是自动存储的,仅此而已,没有任何其它含义。而下面一行语句则指出,这个指针所指向的对象是在堆上面分配的。如果这两行语句出现在一个函数内部,意味着当函数结束时,pObj会被销毁,但是它指向的对象不会。因此,为了继续使用这个对象,通常我们会在函数最后添加一个return语句,或者使用一个传出参数。否则的话,这个在堆上创建的对象就没有指针指向它,也就是说,这个对象造成了内存泄露。


并不是说指针指向的对象都是在堆上创建的。下面的代码如果出现了在函数当中,则是使用指针指向一个在栈上创建的对象:

Object obj;  

Object *pObj = &obj;  


当Object obj不在函数内部,又不是类的成员变量时,这个对象会在全局数据段创建,同理适用于static变量,它们都存在静态区。对于指针Object *pObj;,如果这个语句出现在函数内部或类的成员变量,正如我们前面所说的,这个指针是自动存储的。但是,如果这个语句是在类的外部,它就是在全局数据段创建的。虽然它指向的对象可能在堆上创建,也可能在栈上创建。


总结而言,如果对象通过Object object这种形式创建,则根据自动存储的原则决定对象存于堆还是栈。如果通过new的形式创建,则总是存在堆。而指向对象的指针或者引用的存储地方也是根据自动存储决定。


所以,这里需要注意的可能出现内存泄漏的情况:

1) 函数返回一个局部的对象(栈对象)或局部对象的引用/ 指针,因为局部对象在出了函数体就会被析构掉,你返回的那个地址里面已经没有任何内容了。

例如:

Function void test(){

Object obj;

return object;

return &object;

}

2) 返回指向堆对象的局部的指针:

指向一个new创建的对象,返回后要求程序员记得使用delete函数去释放内存,否则造成内存泄漏。

Object *pObj;  
pObj = new Object;  

return pObj;


当程序员在调用函数的场景下使用另一个指针函数的返回值时,是没有问题的。然而,需要程序员在不需要这个对象的时候,记得使用delete去释放掉堆内存。然而,当这个函数是符号函数的时候,往往会导致忘记了使用delete去释放内存[2]:







这里没办法获取x*y产生的那个指针,因为它已经传给了第二个乘号了。没办法把它拿出来手动delete。


--------------------------------------------------------------------------------------引用和指针的区别--------------------------------------------------------------------------------------


最后,在结束前,讲述一个引用和指针的不同点[2][3]:


(1)引用总是指向一个对象,没有所谓的 null reference .所有当有可能指向一个对象也由可能不指向对象则必须使用指针.由于没有所谓的 null reference 所以所以在使用前不需要进行测试其是否有值.,而使用指针则需要测试其的有效性.
(2)指针可以被重新赋值而reference则总是指向最初或地的对象. 
(3)必须使用reference的场合. Operator[] 操作符 由于该操作符很特别地必须返回 [能够被当做assignment 赋值对象] 的东西,所以需要给他返回一个 reference. 


根据<Effective C++>的描述,引用在C++中是使用指针实现的。不过,指针是一个实体,需要程序在内存开辟空间存储,用以存储地址。sizeof指针返回的是这个指针大小。但引用的本质是一个内存地址(不管是堆、栈还是静态区)的代名,sizeof是其代表的内存的da'xi


需要注意的是:当函数返回值类型为引用时,一般就用引用类型去接收,或者就使用了引用的作用,如果用非引用类型接受,就等于将函数返回的引用的数据值,复制给了该接收对象,和函数返回非引用类型是一样的效果。

--------------------------------------------------------------------------------------使用引用和指针代替函数的值传递机制--------------------------------------------------------------------------------------


这部分内容来自Effective C++(条款20):


在可能的情况下,以pass by reference const代替pass by value,尤其是传递的是自定义类型的对象或者结构体时,复制函数copy产生了很多不必要的消耗。例如:调用该类和其父类的构造函数,再调用该类和其父类的析构函数等。


注意必须要通过const去限制修改传入的引用/ 指针。


Reference:

【1】 http://blog.csdn.net/ac_huang/article/details/38819861

【2】<Effective C++> 

【3】http://blog.csdn.net/dujiangyan101/article/details/2844138


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值